How to access parent's DataContext from a UserControl

后端 未结 4 2075
旧时难觅i
旧时难觅i 2020-12-10 14:25

I need to access the container\'s DataContext from a UserControl (a grid containing textboxes and a listbox: I need to insert items in this list box) that I created in WPF:

相关标签:
4条回答
  • 2020-12-10 14:30

    Add this BindingProxy class to your project:

    using System.Windows;
    
    namespace YourNameSpace
    {
        /// <summary>
        /// Add Proxy <ut:BindingProxy x:Key="Proxy" Data="{Binding}" /> to Resources
        /// Bind like <Element Property="{Binding Data.MyValue, Source={StaticResource Proxy}}" />   
        /// </summary>
        public class BindingProxy : Freezable
        {
            protected override Freezable CreateInstanceCore()
            {
                return new BindingProxy();
            }
    
            public object Data
            {
                get { return (object)GetValue(DataProperty); }
                set { SetValue(DataProperty, value); }
            }
    
            public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy));
        }
    }
    
    1. Add the BindingProxy to your UserControl's resources.
    2. Set the 'Data' property of the BindingProxy to whatever you need, e.g. search for a parent Window. Data="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},Path=DataContext}" If you needed something more complex you could use a custom converter.

    Now you have access to that parent's DataContext: {Binding Data.MyCommand, Source={StaticResource BindingProxy}}

    <UserControl 
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:common="clr-namespace:YourNameSpace;assembly=YourAssembly"
             mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300">
        <UserControl.Resources>
            <common:BindingProxy x:Key="BindingProxy" Data="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},Path=DataContext}" />
        </UserControl.Resources>
        <Border>
            <Button Command="{Binding Data.MyCommand, Source={StaticResource BindingProxy}}">Execute My Command</Button>
            <!-- some visual stuff -->
        </Border>
    </UserControl>
    
    0 讨论(0)
  • 2020-12-10 14:31

    Normally the DataContext will be inherited, just do not explicitly set it on the UserControl and it will get it from its parent. If you have to set it you could still use the Parent property to get the parent, which you then can safe-cast to a FrameworkElement and if it is not null you can grab its DataContext.

    0 讨论(0)
  • 2020-12-10 14:50

    I sometimes have nested User controls and a grandchild usercontrol sometimes needs the grandparent's view's data context. The easiest way I have found so far (and I'm somewhat of a newbie) is to use the following:

    <Shared:GranchildControl DataContext="{Binding RelativeSource={RelativeSource 
                        FindAncestor, AncestorType={x:Type GrandparentView}},
                        Path=DataContext.GrandparentViewModel}" />
    

    I wrote up a more detailed example on my blog if you want more specifics.

    0 讨论(0)
  • 2020-12-10 14:53

    H.B. answers the question in your title.

    However the text poses a different design question. I'd ask you to reconsider your design.

    A control inherits the DataContext property of its ancestor as long as no one in between explicitly overrides.
    If the user control needs data, it should get it from its data source (a viewmodel for the user control). So in this case, the user control can obtain the data it needs from the ListItemsForDisplay property exposed on the SomeViewModel instance. No need to get parent and cast.. much cleaner.

    <ContainerType DataSource={Binding SomeViewModel}>
      <YourUserControl>
        <ListBox ItemsSource={Binding ListItemsForDisplay}"/>
    ...
    
    0 讨论(0)
提交回复
热议问题