データコンテキストが実用的に設定されているタブコントロール内にネストされたデータグリッドにバインドする際の問題

CJウェルッシュ

私はWPFとMVVMに比較的慣れていないので、バインディングが機能しない理由がわかりません。何か提案があれば大歓迎です!

前もって感謝します!

見る

<UserControl x:Class="TestEval.View.BuilderView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" Height="400" Width="300"
         xmlns:vm="clr-namespace:TestEval.ViewModel">
<Grid>
    <TabControl ItemsSource="{Binding Tabs}" SelectedIndex="{Binding SelectedIndex}" HorizontalAlignment="Left" Height="319" Margin="0,81,0,0" VerticalAlignment="Top" Width="300">
        <TabControl.ContentTemplate>
            <DataTemplate>
                <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Path=SelectedEvaluation.Groups}">
                    <DataGrid.Columns>
                        <DataGridTextColumn Header="Group" Binding="{Binding Name}" />
                    </DataGrid.Columns>
                    <DataGrid.RowDetailsTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <DataGrid ItemsSource="{Binding SelectedEvaluation.Groups.Questions}" SelectedItem="{Binding Selected}">
                                    <DataGrid.RowDetailsTemplate>
                                        <DataTemplate>
                                            <StackPanel>
                                                <Label Content="{Binding Content}"></Label>
                                                <Label Content="*" IsEnabled="{Binding IsRequired}" ></Label>
                                                <Label Content="Answer Type:"></Label>

                                            </StackPanel>

                                        </DataTemplate>
                                    </DataGrid.RowDetailsTemplate>
                                </DataGrid>
                            </StackPanel>
                        </DataTemplate>
                    </DataGrid.RowDetailsTemplate>
                </DataGrid>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
    <Button Content="[+] Group" Command="{Binding AddGroupCommand}" HorizontalAlignment="Left" Margin="215,56,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>

モデルを表示

これは、タブを保持し、タブのデータコンテキストを設定するビューモデルです。

    namespace TestEval.ViewModel
    {
        class BuilderViewModel: ViewModelBase
        {
        private ObservableCollection<TabItem> tabs = new ObservableCollection<TabItem>();

        public ObservableCollection<TabItem> Tabs
        {
            get { return tabs; }
            set
            {
                tabs = value;
                OnPropertyChanged("Tabs");
            }
        }

        private int selectedIndex;

        public int SelectedIndex
        {
            get { return selectedIndex; }
            set
            {
                selectedIndex = value;
                SelectedEvaluation = Tabs[selectedIndex].DataContext as EvaluationViewModel;
                OnPropertyChanged("SelectedIndex");
            }
        }

        private EvaluationViewModel selectedEvaluation;

        public EvaluationViewModel SelectedEvaluation
        {
            get
            {
                return selectedEvaluation;
            }
            set
            {
                selectedEvaluation = value;
                OnPropertyChanged("SelectedEvaluation");
            }
        }

        private object selected;

        public object Selected
        {
            get { return selected; }
            set
            {
                if (value == null)
                {
                    return;
                }
                selected = value;
                if (selected is Group)
                {
                    selected = selected as Group;
                }
                else
                {
                    selected = selected as Question;
                }
            }
        }

        private RelayCommand addGroupCommand;

        public ICommand AddGroupCommand
        {
            get
            {
                if (addGroupCommand == null)
                {
                    addGroupCommand = new RelayCommand(p => this.AddGroup(), p => this.CanAddGroup);
                }
                return addGroupCommand;
            }
        }

        public BuilderViewModel()
        {
            Tabs.Add(new TabItem{ Header = "Company Evaluation", DataContext = new EvaluationViewModel("Company") });
            Tabs.Add(new TabItem { Header = "Customer Evaluation", DataContext = new EvaluationViewModel("Customer") });
        SelectedIndex = 0;
        }

        public bool CanAddGroup
        {
            get
            {
                 return SelectedEvaluation != null;
            }

        }

        void AddGroup()
        {
            SelectedEvaluation.Groups.Add(new Group(){Name = "GroupTest"});
        }
    }
}

評価ViewModel

namespace TestEval.ViewModel
{
    public class EvaluationViewModel : ViewModelBase
    {
        private ObservableCollection<Group> groups = new ObservableCollection<Group>();

        public ObservableCollection<Group> Groups
        {
            get { return groups; }
            set
            {
                groups = value;
                OnPropertyChanged("Groups");
            }
        }

        private string name;

        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                OnPropertyChanged("Name");
            }
        }

        public EvaluationViewModel(string name)
        {
            this.Name = name;
        }
   }
}

モデル

グループモデル

namespace TestEval.Model
{
    public class Group : ObservableObject
    {
        private ObservableCollection<Question> questions = new ObservableCollection<Question>();

        public ObservableCollection<Question> Questions
        {
            get { return questions; }
            set
            {
                questions = value;
                OnPropertyChanged("Questions");
            }
        }

        private string name;

        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                OnPropertyChanged("Name");
            }
        }  
    }

}

質問モデル

public class Question : ObservableObject
{
    private Guid id;
    private string content;
    private string answerType;
    private string answers;
    private bool isRequired;
    private string group;
    private bool showAnswers = false;

    public Guid Id
    {
        get { return id; }
        set { id = value; }
    }

    public string Content
    {
        get { return content; }
        set
        {
            content = value;
            OnPropertyChanged("Content");
        }
    }

    public string AnswerType
    {
        get { return answerType; }
        set
        {
            answerType = value;
            if (answerType == "SingleChoice" || answerType == "MultipleChoice")
            {
                ShowAnswers = true;
            }
            else
            {
                ShowAnswers = false;
            }
            OnPropertyChanged("AnswerType");
        }
    }

    public string Answers
    {
        get { return answers; }
        set
        {
            answers = value;
            OnPropertyChanged("Answers");
        }
    }

    public string Group
    {
        get { return group; }
        set
        {
            group = value;
            OnPropertyChanged("Group");
        }

    }

    public bool IsRequired
    {
        get { return isRequired; }
        set
        {
            isRequired = value;
            OnPropertyChanged("IsRequired");
        }
    }

    public bool ShowAnswers
    {
        get { return showAnswers; }
        set
        {
            showAnswers = value;
            OnPropertyChanged("ShowAnswers");
        }
    }

    public Question()
    {

    }

    public Question(string content, string answerType, string answers, bool isRequired)
    {
        this.Id = new Guid();
        this.Content = content;
        this.AnswerType = answerType;
        this.Answers = answers;
        this.IsRequired = isRequired;
    }
}
マークフェルドマン

実際にはそれほど遠くはありません。MVVMでデータバインディングがどのように機能するかについて、いくつかの重要なポイントが欠けているだけだと思います。

最も深刻な問題は、ビューモデルにTabItemの配列があることです。これを行うことは適切なMVVMではありません。実際、決して行われるべきではありません。TabItemはコントロール要素であるため、ビューにのみ属します。タブのビューモデルを作成し、代わりにそれらのコレクションを親ビューモデルに追加してから、TabControlでそれにバインドする必要があります。これが間違っている理由を説明するには、これを試してください。OrientationがVerticalに設定されたStackPanelにグリッドを配置してから、TabItemの同じコレクションにバインドされた重複したTabControlを追加してみてください。TabItemは1つの親しか持つことができず、現在2つにバインドしようとしているため、クリックすると1つのコントロールからタブが消え始めます。

この問題を修正するには、EvaluationViewModelにヘッダーフィールドを追加し、ヘッダーも受け入れるようにコンストラクターを調整します。

    private string _Header;
    public string Header
    {
        get { return this._Header; }
        set { this._Header = value; RaisePropertyChanged(() => this.Header); }
    }

次に、tabsプロパティをに変更します。次のObservableCollection<EvaluationViewModel>ように設定する必要があります。

Tabs.Add(new EvaluationViewModel("Company Evaluation", "Company"));
Tabs.Add(new EvaluationViewModel("Customer Evaluation", "Customer"));
SelectedEvaluation = Tabs.First(); // you'll see why I'm doing this in a moment

タブコントロールに戻ると、TabsItemsが自動的に作成され、それぞれのDataContextが対応するEvaluationViewModelに設定されるため、DisplayMemberPathを設定して、ヘッダーであるフィールドを示し、ビューモデルのSelectedIndexバインディングと対応するSelectedIndexプロパティを削除します(必要ありません)、SelectedItemをSelectedEvaluationプロパティに直接バインドします。TabControlXAMLは次のようになります。

<TabControl ItemsSource="{Binding Tabs}" DisplayMemberPath="Header" SelectedItem="{Binding SelectedEvaluation}" HorizontalAlignment="Left" ... etc...

これで、TabControl.ContentTemplateインスタンス化されると、そのDataContextは対応するタブのDataContextと同じに設定されます。そのテンプレートには、SelectedEvaluationに明示的にバインドしている場所が2つありますつまりSelectedEvaluation.Groups、とSelectedEvaluation.Groups.Questionsです。それらをGroupsとに変更Groups.Questionsます。

最後に、Groupsコレクションを初期化していないのですが、最終的には自分でそれを理解したはずです。

private ObservableCollection<Group> _Groups = new ObservableCollection<Group>();

これはあなたがやろうとしていることを達成するでしょう。何か説明が必要な場合は、ここに投稿してください。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

Related 関連記事

ホットタグ

アーカイブ