Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
630 views
in Technique[技术] by (71.8m points)

xaml - How to do relativesource mode find ancestor (or equivalent) in UWP

I am trying to do something that one would think should be very simple (at least it is in WPF). I have a page with a listbox and a datatemplate, now that datatemplate calls a user control with a button in it. Nothing fancy, but the buttons command is not part of the listboxsource, and I can’t find a simple way to tell the button where to look for the command. Here is the scenario

<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>

Please note this does not compile as in UWP there is no mode find ancestor? How should I do it, I keep looking at google but can’t find anything about it.

Thank you

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The answer is Dependency Property. I have had the same issue. First if you have no DataTemplate involved the solution is straight forward:

(this.Content as FrameworkElement).DataContext = this;

You set the DataContext of the UserControl in its constructor to its code behind.

If you are planning to us your Command inside a DataTemplate you will need a DependecyProperty too.

Example:

 <DataTemplate>
     <Button Command="{Binding DataContext.MyCommand, ElementName=ParentName}">
 </DataTemplate>

And to back it up you create a dependency property for that command:

 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));

So now when you use your user control you will have a MyCommand property on it that you can bind to any command from your ViewModel as long as the templating parent matches the one that you provided and also the parameter is bound to the actual item that the control is part of.

<usercontrols:button MyCommand="{Binding MyCommandFromViewModel}" CommandParameter="{Binding}"/>

Simple example:

UserControl code behind

 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>()));



}

UserControl 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>

Usage in Page.xaml:

<Controls:ListviewUserControl ItemsSource="{Binding ViewModelsItemsList}" ButtonCommand="{Binding ViewModelsCommand}"/>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...