私は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]
コメントを追加