Подтвердить что ты не робот

Как получить доступ к родительскому DataContext из UserControl

Мне нужно получить доступ к контейнеру DataContext из UserControl (сетка, содержащая текстовые поля и список: мне нужно вставить элементы в этот список), который я создал в WPF: какой лучший способ сделать это?

Я думал передать DataContext в качестве параметра пользовательскому элементу управления, но думаю, что есть более чистый способ сделать это.

4b9b3361

Ответ 1

Обычно DataContext будет унаследован, просто не устанавливайте его явно на UserControl, и он получит его от своего родителя, Если вам нужно его установить, вы все равно можете использовать свойство Parent, чтобы получить родителя, который затем можно безопасно отнести к FrameworkElement и если он не является нулевым, вы можете захватить его DataContext.

Ответ 2

У меня иногда есть вложенные элементы управления User, а для пользователя grandchild usercontrol иногда нужен контекст данных представления grandparent. Самый простой способ, который я нашел до сих пор (и я немного новичок), заключается в следующем:

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

Я написал более подробный пример в своем блоге, если вы хотите более подробно.

Ответ 3

Добавьте этот класс BindingProxy к вашему проекту:

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));
    }
}
  • Добавьте BindingProxy в ресурсы UserControl.
  • Задайте свойство Data для BindingProxy на все, что вам нужно, например. поиск родительского окна. Data="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},Path=DataContext}" Если вам нужно что-то более сложное, вы можете использовать собственный конвертер.

Теперь у вас есть доступ к этому родительскому 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>

Ответ 4

H.B. отвечает на вопрос в вашем названии.

Однако текст представляет собой другой вопрос дизайна. Я бы попросил вас пересмотреть свой дизайн.

Элемент управления наследует свойство DataContext своего предка, если никто из них явно не переопределяет.
Если пользовательскому элементу управления нужны данные, он должен получить его из своего источника данных (viewmodel для пользовательского элемента управления). Поэтому в этом случае пользовательский элемент управления может получить нужные ему данные из свойства ListItemsForDisplay, открытого в экземпляре SomeViewModel. Не нужно забирать родителя и бросать.. намного чище.

<ContainerType DataSource={Binding SomeViewModel}>
  <YourUserControl>
    <ListBox ItemsSource={Binding ListItemsForDisplay}"/>
...