[英]Invoke user control function from view model
如何从单独的视图模型调用用户控件上的函数?
在我的场景中,我具有一个带有ScoreDisplay UserControl的“主”视图:
<local:ScoreDisplay/>
该控件将显示我的游戏中n个玩家的得分。 主视图模型连接到游戏控制器,该控制器向其提供分数更新。 我需要将这些更新的分数发送给UserControl(并运行一些动画,非平凡的逻辑等)。
我看到一些选择:
创建一个“分数”依赖项属性,并将其绑定到分数的视图模型集合。 我看到的这种方法的唯一问题是,只要对其进行了修改,就需要查看更改后的内容,以便可以运行适当的动画。 这样做当然是可能的,但似乎并不“正确”。
让ViewModel在UserControl上调用“ UpdateScore”函数。 当然,唯一的问题是ViewModel不应该对View一无所知,因此不应该具有执行此操作所需的引用。
让用户控件注册视图模型上的“ ScoreUpdated”事件。 这似乎是最好的选择,但是我不知道如何获取对ViewModel的引用以注册该事件。
哪种选择是正确的方法? 如果是(2)或(3),如何实现呢?
编辑:
需要明确的是,分数集合中的值正在更改(集合本身保持不变)。 我可以在分数int周围放一个包装纸,然后听PropertyChanged,但是同样,对于一个简单的问题,这似乎过于复杂。 如果这是最好的解决方案,请告诉我!
编辑2:
UpdateScore是一个功能(理论上),它接受更新分数的索引以及要添加到该玩家分数中的值(它可以接受整个分数)。 然后,它使玩家的钉子沿着a脚轨迹移动到新位置。
每当玩家获得积分时都会调用它(这是Cribbage游戏,所以这种情况经常发生)。 视图模型连接到游戏控制器,该控制器引发事件以通知VM玩家已获得积分。 视图模型基本上只需要将此信息传递给ScoreDisplay
进行显示/动画等。
在这种情况下,我们可以应用Mediator
模式,如果成功,则不需要事件。
Mediator模式有多个实施例,但是我最喜欢XAML Guy
的实现,它很简单明了The Mediator Pattern
。
Implementation code
public static class Mediator
{
static IDictionary<string, List<Action<object>>> pl_dict = new Dictionary<string, List<Action<object>>>();
static public void Register(string token, Action<object> callback)
{
if (!pl_dict.ContainsKey(token))
{
var list = new List<Action<object>>();
list.Add(callback);
pl_dict.Add(token, list);
}
else
{
bool found = false;
foreach (var item in pl_dict[token])
if (item.Method.ToString() == callback.Method.ToString())
found = true;
if (!found)
pl_dict[token].Add(callback);
}
}
static public void Unregister(string token, Action<object> callback)
{
if (pl_dict.ContainsKey(token))
{
pl_dict[token].Remove(callback);
}
}
static public void NotifyColleagues(string token, object args)
{
if (pl_dict.ContainsKey(token))
{
foreach (var callback in pl_dict[token])
callback(args);
}
}
}
通过调解器进行的通信如下:
Mediator.NotifyColleagues("NameOfYourAction", ObjectValue);
在这种情况下,我们通知NameOfYourAction
您需要为他传递ObjectValue
。 为了使NameOfYourAction
成功接收数据,必须像下面这样在类或ViewModel
进行注册:
private void NameOfYourAction_Mediator(object args)
{
MyViewModel viewModel = args as MyViewModel;
if (viewModel != null)
viewModel.PropertyA = someValue;
}
// Somewhere, may be in constructor of class
Mediator.Register("NameOfYourAction", NameOfYourAction_Mediator);
在您的情况下,该值将传递ScoreData
ViewModel中的ScoreData
,在此将对其进行更改。
有关使用模式Mediator
更多示例,请参见以下答案:
我找到了一种方法来做到这一点:
我做了一个我的视图模型类型的依赖属性:
public GameViewModel BaseViewModel
{
get { return (GameViewModel)GetValue(baseViewModelProperty); }
set { SetValue(baseViewModelProperty, value); }
}
public static readonly DependencyProperty baseViewModelProperty =
DependencyProperty.Register("BaseViewModel", typeof(GameViewModel), typeof(ScoreDisplay), new PropertyMetadata(null, RegisterForScoreChange));
并将我的XAML更改为:
<local:ScoreDisplay BaseViewModel="{Binding}"/>
然后,在依赖项属性的PropertyChanged事件处理程序中,我可以连接事件。
(e.NewValue as GameViewModel).ScoreUpdated += (d as ScoreDisplay).UpdateScore;
Anatoliy Nikolaev在上面的回答是一个很好的答案。
作为另一种选择,我还建议您调查事件汇总器。 这是一个很好的模式,有很多用途。 他们都将获得对事件聚合器的引用,然后一个可以发布一个事件,另一个可以接收到该事件并可以采取措施。 如果在您的应用程序中启用了类似的功能,则对于多个ViewModel以完全分离的方式进行通信将变得微不足道。 随着额外的奖励测试变得简单,您可以轻松地模拟出Event Aggregator以提供所需的任何数据。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.