如何从DataTemplate绑定到Page的DataContext?

问题描述 投票:1回答:2

我有一个页面,其中DataTemplate用于绑定到该内容的模型,例如:

<DataTemplate x:DataType="models:MyDataType">
    ... content ...
</DataTemplate>

在该内容中,我需要能够绑定Click事件。我需要将click事件存在于视图模型中,该模型被设置为页面的DataContext:

<Page.DataContext>
    <vm:MyViewModel x:Name="ViewModel">
</Page.DataContext>

但我真的很努力让它编译。我尝试的每种方法都会导致编译错误“对象引用未设置为对象的实例”。

我知道我不能使用x:Bind,因为它会绑定到DataTemplate的DataContext,所以我一直在尝试使用Binding,根据我读过的其他SO答案,似乎答案应该是:

Click="{Binding DataContext.Button_Click, ElementName=Page}"

其中Page被定义为x:Page的名称。我试过删除DataContext。我试过添加ViewModel。

我有什么误会?是不是可以做我想做的事情?我尝试使用代码隐藏,但我使用的是模板10,几乎将所有内容都推送到视图模型上,这使我更难以从代码隐藏中访问导航服务等内容。

binding uwp datacontext uwp-xaml template10
2个回答
3
投票

TL;博士;使用消息。

@justinXL是对的,'ElementName'可以工作。但它最好吗?

您尝试解决的问题已通过消息传递解决。大多数MVVM实现包括消息传递解决方案。 Prism使用PubSubEvents; MVVM Light有自己的信使。还有其他人。

这个想法是外部类,通常被描述为message aggregator,负责无状态接收和多播消息。这意味着您需要引用聚合器,但不能引用发送方。很美丽。

例如

常见的用例可能是邮件客户端以及列表中邮件的数据模板如何包含垃圾/删除按钮。单击该按钮时,应该调用什么?通过消息传递,您可以处理模型中的button_press并发送/发布消息(传递项目的消息)。

托管视图模型已订阅聚合器并正在侦听特定消息,即我们刚刚发送的Delete消息。收到后,它会将其从列表中删除,并开始从缓存/数据库或其他任何方式删除它 - 包括提示用户“你确定吗?”

这意味着您的数据模板中的所有数据绑定都是本地的,并且不会扩展到其本地范围之外。为什么这很重要?因为如果使用元素绑定到达托管页面,则意味着您不能1)将此模板移动到资源字典或2)重用此模板。

还有另外两个原因。

  1. 你不能使用编译的x:Bind来做这个,因为它已经限制了这种痛苦的绑定方法的使用 - 这很重要,因为数据模板通常在列表中,并且性能应始终优先,并且
  2. 它增加了相当大的复杂

复杂?

我是复杂解决方案的忠实粉丝。我认为它们很少见,是真正聪明的开发者的商标。我喜欢看这样的代码/解决方案。复杂与复杂不同。谈到复杂性,我不是粉丝。数据绑定已经难以解决;跨范围边界多源数据绑定是纯粹的复杂性。

那就是我所想的。


2
投票

您的绑定表达式是正确的,但它不适用于Button_Click事件处理程序。您需要在页面的ViewModel中定义ICommand

由于你使用的是Template10,你应该能够像这样创建一个名为DelegateCommandClickCommand

private DelegateCommand<MyDataType> _clickCommand;
public DelegateCommand<MyDataType> ClickCommand
{
    get
    {
        _clickCommand = _clickCommand ?? new DelegateCommand<<MyDataType>>((model) =>
        {
            // put your logic here.
        });

        return _clickCommand;
    }
}

绑定将更新为

<Button Command="{Binding DataContext.ClickCommand, ElementName=Page}" CommandParameter="{x:Bind}" />

注意我还添加了一个CommandParameter绑定到按钮,因为您可能想知道哪个MyDataType实例与单击的按钮相关联。

© www.soinside.com 2019 - 2024. All rights reserved.