How to bind from DataTemplate to Page's DataContext?

时间:2017-08-05 12:03:00

标签: binding uwp datacontext uwp-xaml template10

I've got a page where a DataTemplate is being used to bind to the model for that content, e.g.:

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

In that content, I need to be able to bind a Click event. I need that click event to exist in the view model that is set as the page's DataContext:

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

but I'm really struggling with getting it to compile. Every approach I try results in the compilation error "Object reference not set to an instance of an object".

I know I can't use x:Bind because that will bind to the DataTemplate's DataContext, so I've been trying to use Binding and, based on other SO answers I've read, it seems like the answer should be:

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

where Page is defined as the x:Name for the Page. I've tried removing DataContext. I've tried adding ViewModel.

What am I misunderstanding? Is it not possible to do what I want to do? I've tried using code-behind instead but I'm using Template 10 and that pushes almost everything onto the view model, which makes it harder for me to access things like the navigation service from code-behind.

2 个答案:

答案 0 :(得分:3)

<强> TL;博士;使用消息传递。

@justinXL是对的,&#39; ElementName&#39; 可以工作。但它最好吗?

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

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

例如

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

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

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

还有另外两个原因。

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

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

    这就是我的想法。

答案 1 :(得分:2)

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

由于您使用的是 Template10 ,因此您应该可以像这样创建名为DelegateCommand的{​​{1}}

ClickCommand

绑定将更新为

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实例与点击的按钮相关联。

相关问题