3

我试图找到在两个用户控件之间进行通信的最佳方式。我有一个主 XAML 窗口,其中包含两个用户控件,而这两个用户控件又包含各种控件。每个用户控件背后的代码只是将 DataContext 设置为与其关联的视图模型。视图模型包含绑定到控件的对象。我想做的是当用户控件 1 中的列表框更改选择时捕获,新选定的项目将显示在用户控件 2 的编辑框中。由于我正在使用视图模型,因此我无法声明依赖属性我想知道执行此操作的公认方法是什么?我附上了一些基本代码来展示我是如何设置控件的。

主窗口 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>

用户控件 1 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; }
    }
}

用户控件2.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 的选定值?谢谢

4

3 回答 3

5

虽然我知道您在问如何在UserControls之间进行通信,但我建议答案是在视图模型之间进行通信。这可以使用delegate对象轻松实现。通常,您需要一个父视图模型,该模型对两个子视图模型是通用的。

我最近回答了一个类似的问题,所以我不会重复答案。相反,我会要求您查看StackOverflow 上的在视图模型之间传递参数的答案,它通过代码示例解释了解决方案。


更新>>>

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

您可以在父视图模型中创建视图模型实例,而不是在后面的视图代码中创建视图模型实例,并将视图模型连接到视图,如下所示:

Resources

<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

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

于 2013-10-30T15:15:52.960 回答
1

我建议您只有一个 ViewModel 并将 DataContext 绑定到 MainWindow.xaml,而不是对每个 UserControl 执行此操作。

您还应该在 ViewModel 中实现INotifyPropertyChanged以在您更改代码或 ViewModel 的值时通知 UI。

于 2013-10-30T15:12:13.373 回答
0

也许您应该考虑一下您在用户控件中没有依赖属性的自我限制。MVVM 非常适合整体架构,但是如果你把它放到你计划做的每个类和控制中,你可能会做得过火。

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

于 2013-10-30T15:29:16.790 回答