是否有正确的方法来创建包含subViewModel的C#/ WPF ViewModel?
目标是:
我有一个MainWindow。该窗口用于读取/创建图像。窗口上有一个按钮,在2个UserControl和IHM用于读取图像之间切换,另一个用于创建。
MainWindow有一个MainWindowViewModel:
我希望UserControls都可以访问MainWindowViewModel字段/属性并拥有它们自己的命令。
施工将是这样的:
public partial class ReadUserControl : UserControl
{
public ReadUserControl()
{
InitializeComponent();
DataContext = MainViewModel.ReadViewModel;
}
}
public partial class CreateUserControl : UserControl
{
public CreateUserControl()
{
InitializeComponent();
DataContext = MainViewModel.CreateViewModel;
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = MainViewModel;
}
}
例如,如果MainViewModel在CreateUserControl中包含字段ImageWidth设置ImageWidth,则更改ReadUserControl的值。
我希望已经明确,我不知道如何设计我的MainViewModel来实现这个结果
EDIT1:
我已将MainWindowViewModel
创建为单身人士,但我仍然无法获得MainViewModel.CreateViewModel
和MainViewModel.ReadViewModel
public class MainWindowViewModel : ViewModelBase
{
private static MainWindowViewModel _instance = null;
public static MainWindowViewModel Instance
{
get
{
if (_instance == null)
_instance = new MainWindowViewModel();
return _instance;
}
}
private MainWindowViewModel()
: base()
{
}
#region CreateViewModel
/* How to create ? */
#endregion
#region ReadViewModel
/* How to create ? */
#endregion
}
答案 0 :(得分:1)
您的示例将有效。至少如果你已经使MainViewModel成为单身人士。
更多专业方法可能是像这样的构造函数注入。
public partial class ReadUserControl : UserControl
{
public ReadUserControl(MainViewModel vm)
{
InitializeComponent();
DataContext = vm.ReadViewModel;
}
}
使用这样的DependencyInjections,您可以实现更高级别的抽象,因为您的UserControl可以被推广。 (他们都将拥有相同的构造函数)
另一方面,你赋予每个这样的UserControl能力,操纵MainViewModel,不知道副作用。
在你的特殊情况下,将所需的参数传递给UserControl会更安全,而不是给他们提供一堆信息,而他们永远不需要。
public partial class ReadUserControl : UserControl
{
public ReadUserControl(Icommand command, int imageLength, AppParams appParams)
{
InitializeComponent();
...
// Do with your Constructorparameters what ever you have to
}
}
编辑:
这里有一个小而愚蠢的实施 :
<强>代码强>
public class MainViewModel : INotifyPropertyChanged {
private INotifyPropertyChanged _selectedViewModel;
public MainViewModel() {
var cmd = new RelayCommand(x => {
MessageBox.Show("HelloWorld");
}, x => true);
this.RVM = new ReadViewModel(cmd);
this.WVM = new WriteViewModel(cmd);
this.SelectedViewModel = WVM;
}
private ICommand _switchViewModelCommand;
public ICommand SwitchViewModelCommand => this._switchViewModelCommand ?? (this._switchViewModelCommand = new RelayCommand(x => {
if (this.SelectedViewModel == RVM) {
this.SelectedViewModel = WVM;
return;
}
this.SelectedViewModel = RVM;
}));
public INotifyPropertyChanged SelectedViewModel {
get {
return this._selectedViewModel;
}
set {
if (Equals(value, this._selectedViewModel))
return;
this._selectedViewModel = value;
this.OnPropertyChanged();
}
}
public ReadViewModel RVM {
get; set;
}
public WriteViewModel WVM {
get; set;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ReadViewModel : INotifyPropertyChanged {
public ReadViewModel(ICommand sayHelloCommand) {
this.HelloCommand = sayHelloCommand;
}
public ICommand HelloCommand {
get;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class WriteViewModel : INotifyPropertyChanged {
public WriteViewModel(ICommand sayHelloCommand) {
this.HelloCommand = sayHelloCommand;
}
public ICommand HelloCommand {
get;
}
public ICommand HelloMoonCommand => new RelayCommand(x => { MessageBox.Show("Hello Moon"); });
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
<强> XAML 强>
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid Height="200">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<ContentControl Content="{Binding SelectedViewModel, UpdateSourceTrigger=PropertyChanged}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:ReadViewModel}">
<StackPanel>
<Button Content="Say Hello world" Command="{Binding HelloCommand}"></Button>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:WriteViewModel}">
<StackPanel>
<Button Content="Say Hello world" Command="{Binding HelloCommand}"></Button>
<Button Content="Say Hello Moon" Command="{Binding HelloMoonCommand}"></Button>
</StackPanel>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
<Button Content="Switch VM" Command="{Binding SwitchViewModelCommand}" Grid.Row="1"/>
</Grid>
答案 1 :(得分:0)
您可以将MainViewModel作为DataContext传递给您的用户控件,并将元素的数据上下文设置为Read / Create model
类似
<Grid> <!--using MainWindowViewModel as data context-->
<Grid DataContext="{Binding Path=CreateViewModel}"> <!--using CreateViewModel as data context-->
.....
</Grid>
<Grid>