使用子ViewModel创建ViewModel

时间:2016-07-27 13:25:03

标签: c# wpf mvvm

是否有正确的方法来创建包含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.CreateViewModelMainViewModel.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
}

2 个答案:

答案 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>