用户控件之间的 WPF 通信

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19686382/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 09:59:01  来源:igfitidea点击:

WPF Communication between User Controls

c#wpfmvvm

提问by user2936676

I'm trying to find the best way to communicate between two User Controls. I have a main XAML window which contains two User Controls which in turn contain various controls. The Code behind of each User Control simply sets the DataContext to a View Model that is associated to it. The View Model contains objects that are bound to the controls. What I'd like to do is capture when a list box in User Control 1 changes selection, the new selected item be displayed in an edit box in User Control 2. As I'm using View Models I can't declare Dependency Properties so I was wondering what is the accepted way to perform this? I've attached some basic code to show how I'm setting the controls.

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

Main Window XAML

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

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

UserControl1ViewModel.cs

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

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

UserControl2.XAML

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

UserControl2ViewModel.cs

class UserControl2ViewModel
{
    private string text1;

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

How do I get UserControl2.Text1 to be the selected value of UserControl2.Combo1? Thanks

如何让 UserControl2.Text1 成为 UserControl2.Combo1 的选定值?谢谢

回答by Sheridan

While I understand that you are asking how to communicate between UserControls, I would suggest that the answer is to communicate between the view models. This can be easily achieved using delegateobjects. In general, you'd need to have a parent view model that is common to the two child view models.

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

I recently answered a similar question, so I won't duplicate answers. Instead, I would ask you to take a look at the answer from the Passing parameters between viewmodelspost here on StackOverflow which explains the solution with code examples.

我最近回答了一个类似的问题,所以我不会重复答案。相反,我会要求您查看StackOverflow 上发布的 Viewmodels之间传递参数中的答案,该文章通过代码示例解释了解决方案。



UPDATE >>>

更新 >>>

When I said that you need a common parent to your child view models, I don't mean anything to do with inheritance. I just mean that the parent holds a variable instance of each of the child view models... the parent instantiates the child view models.

当我说您的子视图模型需要一个共同的父级时,我的意思与继承无关。我只是说父级持有每个子视图模型的变量实例......父级实例化子视图模型。

Instead of creating the view model instance in the view code behind, you can do it in the parent view model and connect the view models to the views like this:

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

In Resources:

Resources

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

Then you just need to display an instance of the view model and the appropriate view will be displayed:

然后你只需要显示一个视图模型的实例,相应的视图就会显示出来:

In ParentView:

ParentView

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

In ParentViewModel:

ParentViewModel

public BaseViewModel ViewModel { get; set; } // Implement INotifyPropertyChanged

Then when you want to display a new view:

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

ViewModel = new UsersViewModel();

If your child views do not have a BaseViewModeland/or are not interchangable, then you could just add a property for each of them:

如果您的子视图没有BaseViewModel和/或不可互换,那么您可以为每个视图添加一个属性:

public MainViewmodel MainViewModel { get; set; } // Implement INotifyPropertyChanged
public UsersViewmodel UsersViewModel { get; set; } // properly for these properties

Either way, you'll need access to these view models from the parent view if you are going to be able to 'connect them together' with handlers.

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

回答by Kumareshan

I would suggest you, to have only one ViewModel and bind the DataContext to MainWindow.xaml, instead of doing it to each UserControl.

我建议您只使用一个 ViewModel 并将 DataContext 绑定到 MainWindow.xaml,而不是将其绑定到每个 UserControl。

You should also implement INotifyPropertyChangedin your ViewModel to notify the UI whenever you change the value from the code or ViewModel.

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

回答by nvoigt

Maybe you should think about your self-imposed restriction of not having dependency properties in user controls. MVVM is nice for the overal architecture, but you can overdo it if you put it into every class and control you plan to do.

也许你应该考虑一下你自己强加的限制,即在用户控件中没有依赖属性。MVVM 对整体架构来说很好,但如果你把它放在每个类中并控制你计划做的事情,你可能会过度使用它。

If your user controls are just controls for the user, they should behave as such. I have never had to communicate with a TextBoxViewModel or ButtonViewModel, those are controls I simply use. Maybe yours is simple, too and does not need it's own viewmodel. Then you could communicate by using dependency properties as all other controls do.

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