MVVMパターン、ViewModel DataContextの質問
-
05-07-2019 - |
質問
ViewModel間の通信方法を理解する必要があります。私はMVVMが初めてなので、親切にしてください。
これは馬鹿げた例です
クラス定義(ParentViewModelでChild.PropertyChangedイベントをフックしたと仮定):
public class ParentViewModel : ViewModelBase
{
public ChildViewModel Child { get; set; }
}
public class ChildViewModel : ViewModelBase
{
String _FirstName;
public String FirstName
{
get { return _FirstName; }
set
{
_FirstName = value;
OnPropertyChanged("FirstName");
}
}
}
リソースディクショナリに表示されるもの
<DataTemplate DataType="{x:Type vm:ParentViewModel}">
<vw:ParentView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ChildViewModel}">
<vw:ChildView/>
</DataTemplate>
およびChildViewのコードビハインド:
public partial class ChildView : UserControl
{
public QueueView()
{
InitializeComponent();
DataContext = new ChildViewModel();
}
}
明らかな問題は、ChildViewが(DataTemplateからの選択によって)インスタンス化されると、新しいChildViewModelクラスを作成し、ParentViewModelがそれにアクセスできないことです。
では、ViewのDataContextをインスタンス化して、DataTemplateを選択した元のViewModelにするにはどうすればよいですか?
明らかな修正は、ChildViewModelのプロパティをParentViewModelにマージすることですが、再利用のために分離したいです。
答えは些細なものであると確信しています。それが何であるかを知りたいだけです。 :)
事前に感謝します。
解決
次の行を削除するだけです:
DataContext = new ChildViewModel();
ビューの DataContext
は、WPFによって自動的に設定されます。 DataTemplates
のデータコンテキストは、常にテンプレート(この場合はViewModel)のデータに設定されています:
<DataTemplate DataType="{x:Type vm:ChildViewModel}">
<vw:ChildView/>
</DataTemplate>
最終的には、ビューモデルオブジェクト(親クラスと子クラスの両方)を個別に構築し、それらをコンテンツコントロールにプラグインするだけで後で表示できます。
他のヒント
MVVMアプローチを使用してViewModel間で通信する最も簡単な方法は、Mediatorパターン(PrismのEventAggregator)を使用することです。このアプローチの良い例は、次のリンクで見ることができます:
MVVMも確認してくださいサンプルプロジェクトフレームワーク。
QueueViewModelを使用するQueueViewがあるとします。
public class QueueViewModel : INotifyPropertyChanged
{
public ParentType Parent { get; set; }
public QueueViewModel(ParentType parent)
{
this.Parent = parent;
foreach (ChildType child in Parent)
{
child.PropertyChanged += delegate(object sender,
PropertyChangedEventArgs e)
{
if (e.PropertyName != "IsSelected")
return;
//do something like this:
Parent.IsSelected = AllChildrenAreSelected();
};
}
}
}
public class ParentType : INotifyPropertyChanged
{
private bool _isSelected;
public IList<ChildType> Children { get; set; }
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
OnPropertyChanged("IsSelected");
}
}
}
public class ChildType : INotifyPropertyChanged
{
private string _name;
private bool _isSelected;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("Name");
}
}
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
OnPropertyChanged("IsSelected");
}
}
}
-QueueViewパーツ
<StackPanel>
<CheckBlock Text="{Binding Path=Parent.Name}"
IsChecked="{Binding Parent.IsSelected}"/>
<ItemsControl ItemsSource="{Binding Path=Parent.Children}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Path=Name}"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"/>
</DataTemplate>
<ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>