如何在 UWP 中使用相对源模式查找祖先(或等效项)
How to do relativesource mode find ancestor (or equivalent) in UWP
我正在尝试做一些人们认为应该非常简单的事情(至少在 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 中没有找到祖先的模式?怎么办啊,我一直在看google,怎么也找不到。
谢谢
在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" />
参考 -
更新: 要从页面的数据上下文访问删除命令,可以使用以下方法,假设 - 用户控件的数据上下文(从客户)到页面的数据上下文的更改没有'不会影响用户控件中存在的任何其他内容。
<DataTemplate x:Key="MyDataTemplate">
<local:MyButton DataContext="{Binding DataContext, ElementName = PageName}" />
</DataTemplate>
<Button Command="{Binding DeleteCommand}" Content="Delete" />
答案是依赖属性。我有同样的问题。
首先,如果您没有涉及 DataTemplate,则解决方案很简单:
(this.Content as FrameworkElement).DataContext = this;
您在其构造函数中将 UserControl 的 DataContext 设置为其隐藏代码。
如果您计划在 DataTemplate 中使用您的 Command,您也需要 Dependecy属性。
示例:
<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}"/>
我正在尝试做一些人们认为应该非常简单的事情(至少在 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 中没有找到祖先的模式?怎么办啊,我一直在看google,怎么也找不到。
谢谢
在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" />
参考 -
更新: 要从页面的数据上下文访问删除命令,可以使用以下方法,假设 - 用户控件的数据上下文(从客户)到页面的数据上下文的更改没有'不会影响用户控件中存在的任何其他内容。
<DataTemplate x:Key="MyDataTemplate">
<local:MyButton DataContext="{Binding DataContext, ElementName = PageName}" />
</DataTemplate>
<Button Command="{Binding DeleteCommand}" Content="Delete" />
答案是依赖属性。我有同样的问题。 首先,如果您没有涉及 DataTemplate,则解决方案很简单:
(this.Content as FrameworkElement).DataContext = this;
您在其构造函数中将 UserControl 的 DataContext 设置为其隐藏代码。
如果您计划在 DataTemplate 中使用您的 Command,您也需要 Dependecy属性。
示例:
<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}"/>