WPF用户控件之间的通信

4
我正在寻找最佳的方法来在两个用户控件之间进行通信。我有一个主XAML窗口,其中包含两个用户控件,这些控件又包含各种控件。每个用户控件的代码后台只是将DataContext设置为与其关联的View Model。View Model 包含绑定到控件的对象。
我想要做的是捕获当用户控件1中的列表框更改选择时,在用户控件2中显示新选择的项的编辑框。由于我使用了View Models,所以我不能声明Dependency Properties,因此我想知道执行此操作的接受方式是什么?
我附加了一些基本代码,以展示我如何设置控件。
主窗口XAML:
<Window x:Class="CommsTest.View.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:CommsTest.View"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <local:UserControl1 />
    <local:UserControl2 />
</Grid>

UserControl1 XAML

<UserControl x:Class="CommsTest.View.UserControl1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <ComboBox Height="23" HorizontalAlignment="Left" Margin="50,110,0,0" Name="comboBox1" VerticalAlignment="Top" Width="199" ItemsSource="{Binding Combo1}" />
</Grid>

UserControl1ViewModel.cs

class UserControl1ViewModel
{
    private ObservableCollection<string> combo1 = new ObservableCollection<string>();

    public ObservableCollection<string> Combo1
    {
        get { return combo1; }
    }
}

UserControl2.XAML

<UserControl x:Class="CommsTest.View.UserControl2"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <TextBox Height="23" HorizontalAlignment="Left" Margin="63,84,0,0" Name="textBox1" VerticalAlignment="Top" Width="170" Text="{Binding Path=Text1}" />
</Grid>

UserControl2ViewModel.cs

class UserControl2ViewModel
{
    private string text1;

    public string Text1
    {
        get { return text1; }
        set { text1 = value; }
    }
}

如何使UserControl2.Text1成为UserControl2.Combo1的选定值? 谢谢。
3个回答

6
虽然我理解你要问如何在用户控件间通信,但我建议的答案是,在视图模型(view model)间进行通信。这可以通过使用委托对象轻松实现。一般来说,你需要一个父视图模型,它是两个子视图模型的公共部分。
最近我回答了一个类似的问题,因此我不会重复回答。相反,我想让你看一下这里StackOverflow中Passing parameters between viewmodels帖子中的答案,该答案通过代码示例解释了解决方案。

更新 >>>

当我说你需要一个共同的父视图模型时,我并不是指继承。我只是指父视图模型持有每个子视图模型的变量实例...父视图模型实例化子视图模型。

你可以在父视图模型中创建视图模型实例,而不是在视图代码后台创建,并像这样将视图模型连接到视图:

资源中:

<DataTemplate DataType="{x:Type ViewModels:MainViewModel}">
    <Views:MainView />
</DataTemplate>
...
<DataTemplate DataType="{x:Type ViewModels:UsersViewModel}">
    <Views:UsersView />
</DataTemplate>

接着,您只需要显示视图模型的一个实例,相应的视图就会被显示出来:

ParentView中:

<ContentControl Content="{Binding ViewModel}" />

ParentViewModel中:
public BaseViewModel ViewModel { get; set; } // Implement INotifyPropertyChanged

然后当你想要显示一个新视图时:

ViewModel = new UsersViewModel();

如果您的子视图没有BaseViewModel,或者它们不可互换,则可以为每个子视图添加一个属性:
public MainViewmodel MainViewModel { get; set; } // Implement INotifyPropertyChanged
public UsersViewmodel UsersViewModel { get; set; } // properly for these properties

无论如何,如果您要能够使用处理程序“将它们连接在一起”,则需要从父视图访问这些视图模型。

Sheridan,感谢您的回答,我认为这是一个非常整洁的解决方案。我只是在理解视图模型对象的实例化方面遇到了困难。在您的示例中,父视图模型正在创建子视图模型的实例,如果子视图模型是从父视图模型继承而来的(您没有说明,但我假设这就是您的意思),这不会创建问题吗?此外,我正在视图代码后台中创建视图模型的实例,以便可以将DataContext设置为它们。再次感谢。 - user2936676

1
我建议您只使用一个ViewModel,并将DataContext绑定到MainWindow.xaml,而不是每个UserControl都这样做。
您还应该在ViewModel中实现INotifyPropertyChanged,以便在代码或ViewModel更改值时通知UI。

嗨,Kumareshan,我想我没有解释清楚,我保持了示例的简单性以便更加清晰易懂。实际上,我将拥有大量用户控件,并且只有一个视图模型会变得非常混乱。我没有展示INotifyPropertyChanged的实现,以尽可能减小代码量,但我应该在我的问题中解释清楚这一点。谢谢。 - user2936676

0

也许你应该考虑一下自己对用户控件中没有依赖属性的限制。MVVM 对于整体架构来说很好,但如果你把它放到每个类和控件中,就会过度使用。

如果你的用户控件只是用于用户的控件,那么它们应该像这样运作。我从未需要与 TextBoxViewModel 或 ButtonViewModel 通信,它们只是我简单使用的控件。也许你的控件也很简单,不需要自己的视图模型。那么你可以像所有其他控件一样使用依赖属性进行通信。


有道理。这引发了一个关于View中应该有多少代码的辩论。这是我尝试将所有处理放在视图模型中的第一个项目,我发现有些地方很困难。 - user2936676

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接