WPF/XAML - 将控制命令绑定到父窗口的视图模型?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11748501/
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 04:47:48  来源:igfitidea点击:

WPF/XAML - binding control commands to parent window's viewmodel?

wpfxaml

提问by Jeff Dege

I have an application, and I have an assembly.

我有一个应用程序,我有一个程序集。

In the application, I have a window, and in the assembly I have a user control.

在应用程序中,我有一个窗口,在程序集中我有一个用户控件。

There is an instance of the user control in the window.

窗口中有一个用户控件的实例。

Both the user control and the window are backed by separate viewmodels.

用户控件和窗口都由单独的视图模型支持。

In the user control, there is a button. The button should be enabled/disabled based on the state of the user control's viewmodel. When the button is clicked, processing needs to be done, based on the information in the user control's viewmodel, but it needs to be done by the window's viewmodel. (There are aspects of what needs to be done that are, and should be, outside of the scope of the user control.)

在用户控件中,有一个按钮。该按钮应根据用户控件的视图模型的状态启用/禁用。当按钮被点击时,需要根据用户控件的viewmodel中的信息进行处理,但需要由窗口的viewmodel来完成。(需要做的事情的某些方面是并且应该在用户控制范围之外。)

And here's the twist - this user control won't be used exclusively in this window, it might be used in another, or in a control that is used in a third. The user control can't be allowed to know what kind of window or control contains it, or is handling the process when its button is clicked.

这里有一个转折点——这个用户控件不会专门在这个窗口中使用,它可能会在另一个窗口中使用,或者在第三个使用的控件中使用。不能让用户控件知道包含它的窗口或控件的类型,或者在单击其按钮时正在处理该过程。

So, what to do?

那么该怎么办?

Define a command in the assembly, and bind the user control's button to it, passing the user control's viewmodel as the command parameter? How, then, do I bind the command to the window's viewmodel?

在程序集中定义一个命令,并将用户控件的按钮绑定到它,将用户控件的视图模型作为命令参数传递?那么,如何将命令绑定到窗口的视图模型?

Or should I define the command in the user control's viewmodel, then raise an event to tell the parent window that the appropriate action needs to be taken?

或者我应该在用户控件的视图模型中定义命令,然后引发一个事件来告诉父窗口需要采取适当的操作?

It's not clear to me which is cleaner.

我不清楚哪个更清洁。

回答by Josh

If you always know that the parent's property is going to be exposed the same with the same name, you can do something like this that has worked for me plenty of times:

如果您始终知道父项的属性将以相同的名称公开,那么您可以执行以下操作,这对我来说已经很多次了:

Command={Binding Parent.DataContext.SomeCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}

This gets the usercontrol, then goes to the parent and gets that datacontext and binds it to that command. This works when the user control will be encompassed by many windows / controls that expose the same command (you could implement an interface here).

这将获取用户控件,然后转到父控件并获取该数据上下文并将其绑定到该命令。当用户控件被许多公开相同命令的窗口/控件包含时,这会起作用(您可以在此处实现一个接口)。

You could then pass the user control's viewmodel to the command (again, implement some interface) like so:

然后,您可以将用户控件的视图模型传递给命令(再次实现一些接口),如下所示:

CommandParaemter={Binding }

回答by LadderLogic

There should be hierarchy with your view models, just like you have with your controls. The main window has a child user-control. The Main View Model should be able to get connected with User Control View Model (and assign it if needed). Here is how I would do it:

你的视图模型应该有层次结构,就像你的控件一样。主窗口有一个子用户控件。主视图模型应该能够与用户控制视图模型连接(并在需要时分配它)。这是我将如何做到的:

public class MainVM:NotificationObject
{
  // Make this a Notify Property
  public UserVM userVM { get{return _userVM;}; set {_userVM = value; RaisePropertyChanged("userVM");}

  public MainVM
{
  userVM = new UserVM();
  userVM.ExecuteCmd = new DelegateCommand (yourAction);

}

}

public class UserVM:NotificationObject
{

public DelegateCommand ExecuteCmd {get{return _executeCmd;} set{_executeCmd = value; RaisePropertyChanged("ExecuteCmd");
}

}

XAML:

XAML:

<local:urUserCtrl DataContext={Binding userVM}/>

This is of course psuedocode

这当然是伪代码

回答by Neutrino

Sounds like a case for the Strategy pattern. http://en.wikipedia.org/wiki/Strategy_pattern

听起来像是策略模式的一个例子。http://en.wikipedia.org/wiki/Strategy_pattern

Define an interface for a strategy object that can be assigned to the UserControl's viewmodel, (or used to initialise it). The interface defines whatever properties/methods/events are required to enable the strategy object to retrieve from the UserControl viewmodel the data needed for the processing, plus a means of returning the result of the processing back to the UserControl viewmodel.

为可以分配给 UserControl 的视图模型(或用于初始化它)的策略对象定义一个接口。该接口定义了使策略对象能够从 UserControl 视图模型检索处理所需的数据所需的任何属性/方法/事件,以及将处理结果返回给 UserControl 视图模型的方法。

Then create a concrete implementation of that strategy object that collaberates with the Window's viewmodel to perform whatever task it needs to. In this case the Window's viewmodel might even implement the strategy interface itself.

然后创建该策略对象的具体实现,该对象与 Window 的视图模型协作以执行它需要的任何任务。在这种情况下,Window 的视图模型甚至可能实现策略接口本身。

Other instances of the UserControl in other scenarios can then be initialised with other concrete implementations of the strategy object that perform the same required task, but possibly in very different ways.

然后可以使用执行相同所需任务的策略对象的其他具体实现来初始化其他场景中 UserControl 的其他实例,但可能以非常不同的方式进行初始化。

回答by Erno

You could use a Messenger structure to communicate between ViewModels.

您可以使用 Messenger 结构在 ViewModel 之间进行通信。

MVVMLight contains onethat you could use or you could write your own.

MVVMLight 包含一个您可以使用或您可以自己编写的。

Before doing this make sure you did separate the responsibilities correctly or you'll end up with spaghetti-messages-code.

在执行此操作之前,请确保您正确分离了职责,否则最终会得到 spaghetti-messages-code。