我的View中的代码背后有一个方法(这个方法对我的UI做了一些事情)。
无论如何,我想从我的ViewModel中触发这个方法。怎么可以这样做?
答案 0 :(得分:21)
我(也许是其他人?)MVVM的难点在于理解一件简单的事情: View了解ViewModel 。我使用的是绑定和命令,但在strings
中它们很简单xaml
。由于在运行时安全解析(安全意味着你可以做错字,但软件不会崩溃)这使得视图解耦从视图模型(至少在编译时)。我一直在寻找解决方案,以保持这种脱钩,例如,行为。
事实是,您可以直接访问视图模型,该模型通常是窗口/用户控件的DataContext
:
var vm = (MyViewModel)this.DataContext;
知道使用事件可能是从视图模型调用视图方法的最佳方法,因为视图模型不知道是否有订阅者,它只是触发该事件和事件可以被视图或其他视图模型使用。 / p>
// define in the view model
public delegate void MyEventAction(string someParameter, ...);
public event MyEventAction MyEvent;
// rise event when you need to
MyEvent?.Invoke("123", ...);
// in the view
var vm = (MyViewModel)DataContext;
vm.MyEvent += (someParameter, ...) => ... // do something
答案 1 :(得分:2)
You can do it like this in View (code behind).
It casts to an interface to be implemented by the ViewModel, so that you are not constrained to one specific ViewModel type.
// CONSTRUCTOR
public SomeView()
{
InitializeComponent();
DataContextChanged += DataContextChangedHandler;
}
void DataContextChangedHandler(object sender, DependencyPropertyChangedEventArgs e)
{
var viewModel = e.NewValue as IInterfaceToBeImplementedByViewModel;
if (viewModel != null)
{
viewModel.SomeEvent += (sender, args) => { someMethod(); }
}
}
答案 2 :(得分:1)
根据MVVM pattern ViewModel不知道View,所以这是不可接受的。要与ViewModel View进行交互,可以触发命令,也可以使用绑定。此外,您不应将特定于UI的东西(如BusyIndicator)移动到ViewModel级别。
请提供更多有关您的具体用例的详细信息 - 当您想要调用View的方法以及此方法的用途时。
答案 3 :(得分:0)
我看到你回复上面的答案,你说你希望你的ViewModel检索数据然后告诉你的视图停止繁忙的指示。
我不确定我的解决方案是否是最佳解决方案,但您可以尝试一下,如果我错了,也许有人可以纠正。
因此,从您的角度来看,您将从ViewModel调用一个方法来开始读取数据集,对吗?在此方法中,您可以传递委托(指向视图中存在的方法),当ViewModel完成从服务器读取数据集时,触发链接到视图中的方法的委托(来自您的viewmodel)可以停止忙碌的指示灯。
所以在你看来你有
void StopBusyIndicator()
{
this.BusyIndicator.IsBusy = false;
}
当您调用ViewModel读取数据集时,
这样称呼:
ViewModel.ReadDataSet( ()= >StopBusyIndicator)
它将StopBusyIndicator方法作为委托传递,您可以在ReadDataSet的末尾调用它。
HTH
答案 4 :(得分:0)
您可以编写一个接受数据传输对象的操作类。在DTO中,添加一个名为“View”的属性并为其指定当前视图。通过控制器从视图的代码隐藏中调用操作,取消打开DTO,现在您可以完全控制操作类中的视图。
如果您真的想在模型中执行此操作,只需在模型中使用“View”类型参数创建方法并执行它,并传入当前视图。
答案 5 :(得分:0)
假设您在我的登录视图背后的代码中有一个方法,它通过在登录失败时将焦点移到 PasswordEntry 来更新 UI,那么从您的 ViewModel 触发此方法的最简单和最通用的方法是使用 {{3 }}。
正如您在 Action delegates 中看到的,您需要添加的全部内容是您的服务确定登录失败并且您希望密码条目获得焦点,是您的 ViewModel 中的两行代码和一个视图中的操作处理程序。
视图模型代码:
<Form ref={this.formRef} name="control-ref">code goes here.........</Form>
&public Action<bool> OnLoginFailed { get; set; }
查看代码:
OnLoginFailed?.Invoke(true);