如何在 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 - 如何获取源域信息?

jQuery 遍历 - 祖先:向上遍历 DOM 树,以查找元素的祖先

一个人如何在一组给定的数据中存储和查找祖先?

Navicat 教程:如何进行搜索筛选

Navicat 教程:如何进行搜索筛选

如何使用 AdvancedCollectionView 源更新 UWP ListView 中的项目