如何在 UWP 中进行相对源模式查找祖先(或等价物)
Posted
技术标签:
【中文标题】如何在 UWP 中进行相对源模式查找祖先(或等价物)【英文标题】:How to do relativesource mode find ancestor (or equivalent) in UWP 【发布时间】:2015-12-27 23:23:49 【问题描述】:我正在尝试做一些人们认为应该非常简单的事情(至少它在 WPF 中)。 我有一个带有列表框和数据模板的页面,现在该数据模板调用了一个带有按钮的用户控件。没什么特别的,但是按钮命令不是列表框源的一部分,我找不到简单的方法来告诉按钮在哪里寻找命令。这是场景
<Page x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1">
<Page.Resources>
<DataTemplate x:Key="MyDataTemplate">
<local:MyButton />
</DataTemplate>
</Page.Resources>
<ListBox ItemTemplate="StaticResource MyDataTemplate" ItemsSource="Binding Customers" />
</Page>
<UserControl x:Class="App1.MyButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button Command="Binding RelativeSource=RelativeSource Mode=FindAncestor, AncestorType=UserControl, AncestorLevel=2, Path=DataContext.DeleteCommand" Content="Delete" />
</UserControl>
请注意这不会编译,因为在 UWP 中没有模式查找祖先?我该怎么办,我一直在看谷歌,但找不到任何相关信息。
谢谢
【问题讨论】:
我在***.com/a/43399114/303612 分享了一个使用附加属性和RelativeSource 自绑定的解决方案 【参考方案1】:答案是依赖属性。我有同样的问题。 首先,如果您没有涉及 DataTemplate,则解决方案很简单:
(this.Content as FrameworkElement).DataContext = this;
您在其构造函数中将 UserControl 的 DataContext 设置为其后面的代码。
如果您打算在 DataTemplate 中使用您的命令,您也需要一个 DependecyProperty。
例子:
<DataTemplate>
<Button Command="Binding DataContext.MyCommand, ElementName=ParentName">
</DataTemplate>
为了备份它,您为该命令创建一个依赖属性:
public ICommand MyCommand
get return (ICommand)GetValue(MyCommandProperty);
set SetValue(MyCommandProperty, value);
// Using a DependencyProperty as the backing store for MyCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyCommandProperty =
DependencyProperty.Register("MyCommand", typeof(ICommand), typeof(ownerclass), new PropertyMetadata(0));
所以现在,当您使用用户控件时,您将拥有一个 MyCommand 属性,您可以将其绑定到 ViewModel 中的任何命令,只要模板父级与您提供的匹配并且参数绑定到实际控件所属的项目。
<usercontrols:button MyCommand="Binding MyCommandFromViewModel" CommandParameter="Binding"/>
简单示例:
UserControl 后面的代码
public sealed partial class ListviewUserControl : UserControl
public ListviewUserControl()
this.InitializeComponent();
(this.Content as FrameworkElement).DataContext = this;
public ICommand ButtonCommand
get return (ICommand)GetValue(ButtonCommandProperty);
set SetValue(ButtonCommandProperty, value);
// Using a DependencyProperty as the backing store for ButtonCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ButtonCommandProperty =
DependencyProperty.Register("ButtonCommand", typeof(ICommand), typeof(ListviewUserControl), new PropertyMetadata(null));
public ObservableCollection<Item> ItemsSource
get return (ObservableCollection<Item>)GetValue(ItemsSourceProperty);
set SetValue(ItemsSourceProperty, value);
// Using a DependencyProperty as the backing store for ItemsSource. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(ObservableCollection<Item>), typeof(ListviewUserControl), new PropertyMetadata(new ObservableCollection<Item>()));
用户控件 Xaml:
<Grid>
<ListView ItemsSource="Binding ItemSource" x:Name="ListView">
<ListView.ItemTemplate>
<DataTemplate>
<!--some item related content-->
<AppBarButton Icon="Delete" Command="Binding ButtonCommand, ElementName=ListView" CommandParameter="Binding"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
Page.xaml 中的用法:
<Controls:ListviewUserControl ItemsSource="Binding ViewModelsItemsList" ButtonCommand="Binding ViewModelsCommand"/>
【讨论】:
我没有得到最后一部分绑定需要在 usercontrols 中看起来像什么:按钮,按钮 command=Binding MyCommand 不做任何事情,按钮必须查看模板化的父级或者找到依赖属性的东西? 依赖属性总是在usercontrols代码后面。并且它唯一允许在用户控件中的对象与其外部之间进行绑定。有时我将整个 ListView 放入用户控件并为 ItemSource 创建一个依赖项属性,这样我就可以在不同的视图中重用整个列表,我只需要绑定 ItemSource 和不同的命令及其标签,如果他们改变 我明白了,现在有道理了,我稍后会测试它:) 非常感谢你:) 别担心,我很高兴它有帮助......首先有点令人困惑,但一旦你得到它......【参考方案2】:Windows 10 UWP 中有一个名为x:Bind
的概念。在x:Bind
中,后面的代码成为绑定的数据上下文。所以如果你在用户控件的代码后面添加一个属性,指向视图模型,可以用来绑定命令。
public class MyButton
public ViewModel ButtonViewModel
get
return ButtonViewModelObject;
在 XAML 中 -
<Button Command="x:Bind ButtonViewModel.DeleteCommand" Content="Delete" />
参考 - https://msdn.microsoft.com/en-us/library/windows/apps/mt204783.aspx
OR
您可以使用 ElementName 与传统绑定来实现。
<Button Command="Binding DataContext.DeleteCommand, ElementName= UserControlName" Content="Delete" />
参考 - Can't access datacontext of parent
更新:要从页面的数据上下文访问删除命令,可以使用以下方法,假设 - 用户控件的数据上下文(来自客户)到页面的数据上下文的更改不会影响其他任何存在在用户控件内部。
<DataTemplate x:Key="MyDataTemplate">
<local:MyButton DataContext="Binding DataContext, ElementName = PageName" />
</DataTemplate>
<Button Command="Binding DeleteCommand" Content="Delete" />
【讨论】:
谢谢你的回答,但这对我来说不是一个好的解决方案,因为我把那个按钮放到了一个单独的用户控件中,所以我可以在很多地方重复使用它。所以 ViewModel 在不同的屏幕上会有所不同。相对源允许忽略它是哪个视图模型,它只会查看父级的数据上下文。我已经尝试过 ElementName,但在这种情况下它不起作用,它找不到调用页面的名称。 @adminSoftDK: 是不是像 - 您在数据模板内的用户控件中有按钮,而删除命令在带有ListBox
的页面的数据上下文中?
是的,deletecommand在页面的datacontext中,但是datatemplate的当前datacontext是每个客户。
我应该做一个更好的例子,我也试过这个。这几乎就在那里,但我还将当前项目的 Id 作为命令参数传递。它们属于原始数据上下文,因此通过执行您刚才所说的命令将被找到,但现在我对命令参数有相同的情况。以上是关于如何在 UWP 中进行相对源模式查找祖先(或等价物)的主要内容,如果未能解决你的问题,请参考以下文章
来自 Chrome 的 UWP UserNotification - 如何获取源域信息?