2016-07-27 70 views
1

是否有一个正确的方法来创建一个包含subViewModel的C#/ WPF ViewModel?创建一个ViewModel与子ViewModel

目标是:

我有一个MainWindow。该窗口用于读取/创建图像。在那个窗口上有一个按钮,用户可以在2个UserControl之间切换,IHM用于读取图像,另一个用于创建。

的主窗口具有带有MainWindowViewModel:

  • 命令开关
  • 图像长度
  • 应用参数

我想,这两个用户控件可存取权限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包含一个字段ImageWidth在CreateUserControl设置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 
} 

回答

1

你的例子会工作。至少如果你已经使你的MainViewModel是一个单例。

更多专业方法可能是像这样的构造器注入。

public partial class ReadUserControl : UserControl 
{ 
    public ReadUserControl(MainViewModel vm) 
    { 
     InitializeComponent(); 
     DataContext = vm.ReadViewModel; 
    } 
} 

有了这样的依赖注入,您可以实现更高级别的抽象,因为您的UserControls可以被推广。 (他们都将具有相同的构造函数)

另一方面,您给每个这样的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> 
+0

我添加了EDIT1:MainWindowViewModel作为辛格尔顿似乎是个好主意,但我不知道如何创建subViewModels(添加参数将很难维护,因为我将添加其他参数,而且我是唯一一个开发此应用程序的人,我可以避免副作用) –

+0

我正在做一个小实例...给我第二个 – lokusking

+0

@ A.Pissica t添加示例。注意:一切都符合MVVM并且没有代码隐藏。 DataContext由'DataTemplate'设置。另外,你有一个构造器的例子注入 – lokusking

0

您可以在MainViewModel作为DataContext的传递你的用户控制和设置元素读取的数据上下文/创建模型

<Grid> <!--using MainWindowViewModel as data context--> 
    <Grid DataContext="{Binding Path=CreateViewModel}"> <!--using CreateViewModel as data context--> 
      ..... 
    </Grid> 
<Grid>