首页 > 解决方案 > 具有 wpf 视图的类库的 2 个视图(相同实例)的 1 个 ViewModel

问题描述

请耐心等待,因为我对这一切还很陌生。我目前正在尝试将我的两个视图绑定到我的 ViewModel 的同一个实例(在 xaml 中不是代码隐藏)。我的代码用于软件中的插件(输出是类库 .dll 文件),因此它没有设置为 C# WPF 应用程序(我没有 App.xaml)。我已经研究过使用 MVVM light、viewmodellocator 和在线找到的所有其他解决方案,但它们都依赖于 App.xaml,我不确定如何在我的情况下实现。

根据我正在为其开发插件的软件文档;入口点是一个特定的类(现在称之为 EntryPoint.cs)。Main 方法用于进入。在我的 Main 方法中,我创建了 MainView。

入口点.cs:

public class EntryPoint
{
    private MainView _MyForm;

    public void Main(...)
    {
            ....
            _MyForm = new MainView();
            _MyForm.ShowDialog();

    }
}

在我的主视图构造函数中,我启动了我的 MainWindowViewModel。

Mainview.cs:

public partial class MainView : Window
{

    public MainView()
    {
        InitializeComponent();
        this.DataContext = new MainWindowViewModel();
    }


}

SecondView 由我的 MainView 上的按钮打开,如下所示;这是来自我的 MainWindowViewModel 的代码片段,其中包含打开我的 SecondView 的命令:

 public void OpenSecondView()
    {
        ....

        SecondView newView = new SecondView (this);
        SecondView.Show();
    }

我之前通过在我的 SecondView 的构造函数中将视图模型作为参数传递来在我的代码隐藏中设置数据上下文:

public partial class SecondView: Window
{
public SecondView(MainViewModel viewModel)
    {
        InitializeComponent();
        this.DataContext = viewModel;
    }
}

如何在我的 xaml 中实现这一点?我想绑定到我的 viewModel 的同一个实例。有什么指导吗?

标签: c#wpfxamlmvvmdata-binding

解决方案


试试这个:

主视图.cs

public partial class MainView : Window
{

    public MainView()
    {
        InitializeComponent();
        var vm = new MainWindowViewModel();
        vm.PropertyChanged += OnViewModelPropertyChanged;
        this.DataContext = vm;
    }

    public void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof("OpenSecondViewCommand")
        {
            SecondView newView = new SecondView() { DataContext = this.DataContext };
            SecondView.Show();
        }
    }

MainWindowViewModel.cs

// Get rid of your OpenSecondView() method that is tied to your Command. It is too tightly-
// coupled with the View. Instead, just use your Command public property and trigger the 
// PropertyChanged event, then let the View layer deal with what happens when you trigger 
// this Command. I don't know the name of your Command public property so I'm just going
// to assume it's called OpenSecondViewCommand. Something like this would suffice:

private RelayCommand openSecondViewCommand;
public RelayCommand OpenSecondViewCommand
{
    get
    {
        if (this.openSecondViewCommand == null)
            this.openSecondViewCommand = new RelayCommand(() => PropertyChanged?.Invoke(this, new PropertyEventArgs(nameof(OpenSecondViewCommand)));
        return this.openSecondViewCommand;
    }
}

第二视图.cs

// Remove the MainWindowViewModel parameter from your c'tor.  
// Change it back to the way it was originally.

public partial class SecondView: Window
{
    public SecondView()
    {
        InitializeComponent();
    }
}

详细说明

MVVM 设计模式的主要方面之一是通过将模型与视图模型以及视图模型与视图分离和解耦来定义“关注点分离”。此设计模式以这种方式定义它,以便您可以用新的 UI 替换整个 UI,而无需接触您的 ViewModel 代码。在您的情况下,您已将您的嵌入SecondView到您的MainWindowViewModel. 这违反了 MVVM 设计模式。

将两个 View 绑定到同一个 ViewModel 就像确保两个 View 具有相同的DataContext. 您可以看到我已经MainView.cs通过将SecondView DataContext属性设置为MainView DataContext.

SecondView newView = new SecondView() { DataContext = this.DataContext };

推荐阅读