c# - 使用子 ViewModel 创建 ViewModel

标签 c# wpf mvvm

是否有适当的方法来创建包含 subViewModel 的 C#/WPF ViewModel ?

目标是:

我有一个主窗口。该窗口用于读取/创建图像。窗口上有一个按钮,可以在 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 包含字段 ImageWidth,则 CreateUserControl 中的 ImageWidth 设置更改 ReadUserControl 的值。

    我希望已经清楚了,我不知道如何设计我的 MainViewModel 来达到这个结果

    编辑1:

    我创建了 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
    }
    

    最佳答案

    您的示例将起作用。至少如果您已将 MainViewModel 设为 Singleton。

    更专业的方法可能是像这样的构造函数注入(inject)。

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

    使用此类 DependencyInjections,您可以实现更高级别的抽象,因为您的 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>
    

    关于c# - 使用子 ViewModel 创建 ViewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38614294/

    相关文章:

    c# - 每秒抛出的 .NET 异常图表?

    wpf - MVVM 模式违规 : MediaElement. Play()

    c# - App Current Shutdown关闭窗口提示

    android - 使用 LiveData 在 SeekBar 和 EditText 中取得进展

    c# - 使用 MVVM 对 ComboBox 选择的异步方法调用

    android - 获取 ViewModel ViewModelProvider.Factory 和应用上下文

    c# - 具有状态构造函数参数的 Akka .NET 中的依赖注入(inject)

    c# - 直通读取文件夹中的所有文件

    c# - 在 PowerShell 中使用带有重载算术运算符的自定义 .NET 类

    c# - MultiBinding 转换器未绑定(bind)到 DataTemplate 中的 TextBlock