2014-12-17 6 views
1

Я добавил DependencyProperty к моему представлению, привязанный к работе DependencyProperty, но только если я не устанавливаю DataContext.Свойство DependencyProperty UserControl равно null, когда UserControl имеет DataContext

GenericView.xaml

<UserControl x:Class="GenericProject.View.GenericView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <StackPanel> 
     <Button Command="{Binding VMFactory.CreateViewModelCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> 
     <TextBox IsEnabled="False" Text="{Binding SomeProperty, Mode=OneWay}" /> 
    </StackPanel> 
</UserControl> 

GenericView.xaml.cs

public partial class GenericView : UserControl 
{ 
    // The DependencyProperty for VMFactory. 
    public static readonly DependencyProperty VMFactoryProperty = DependencyProperty.Register("VMFactory", typeof(VMFactoryViewModel<GenericViewModel>), typeof(GenericView)); 

    public VMFactoryViewModel<GenericViewModel> VMFactory 
    { 
     get { return (VMFactoryViewModel<GenericViewModel>)GetValue(VMFactoryProperty); } 
     set { SetValue(VMFactoryProperty, value); } 
    } 

    public GenericView() 
    { 
     InitializeComponent(); 
    } 
} 

Здесь я создаю два вида, чтобы проиллюстрировать проблему под рукой. Взаимодействие VMFactory в первом представлении не будет выполнено, потому что у меня установлен DataContext. Вторая точка зрения будет успешной, в чем причина такого поведения?

MainPage.xaml

<vw:GenericView DataContext="{Binding Generic}" VMFactory="{Binding GenericFactory}" /> 
<vw:GenericView VMFactory="{Binding GenericFactory}" /> 
+1

(Пожалуйста, игнорируйте этот ranty комментарий, если он не применяется!) Вы не создаете ViewModels инкапсулировать логику вашего UserControls, не так ли? Потому что нет. Вы НЕ создаете ViewModel для своих UserControls. UserControls должен содержать только логику пользовательского интерфейса, и они должны быть сконструированы так же, как и любой другой элемент управления. Имеет ли TextBox TextBoxViewModel? ** NO. ** PITA, с которым вы сталкиваетесь, заключается в том, что вы пытаетесь внедрить антипаттерн. Прекрати это. Вот мой ответ с более подробной информацией. Http://stackoverflow.com/a/25796096/1228 – Will

+0

@ Если я этого не сделаю, UserControl просто должен предоставить доступ к команде, которая находится за пределами DataContext. –

+1

... ... wut? Пользователь UserControl не должен иметь команду, которую он выставляет, он должен иметь открытый DP типа ICommand, который он использует, чтобы позволить другим виртуальным машинам связывать * свои * команды с ним. У вас не должно быть VMFactoryUserControl и VMFactoryViewModel. Это запах кода прямо там. Поэтому я не понимаю, что вы здесь делаете, я думаю. – Will

ответ

0

У меня есть рабочее решение, кажется, что свойства элемента управления связаны с DataContext элемента управления?

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

GenericView.xaml

<!-- Everything in here was correct. --> 
<UserControl x:Class="GenericProject.View.GenericView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <StackPanel> 
     <Button Command="{Binding VMFactory.CreateViewModelCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> 
     <TextBox IsEnabled="False" Text="{Binding SomeProperty, Mode=OneWay}" /> 
    </StackPanel> 
</UserControl> 

MainPage.xaml

<!-- This is where I messed up earlier, VMFactory requires a relative binding. --> 
<vw:GenericView DataContext="{Binding Generic}" 
       VMFactory="{Binding DataContext.GenericFactory, RelativeSource={RelativeSource AncestorType={x:Type Page}}}" /> 
4

Это довольно распространенное Binding "Гоча" ...

Чтобы получить доступ к VMFactory, вы должны связать ваш UserControl к себе, используя ...

DataContext="{Binding RelativeSource={RelativeSource Self}}" 

Вы не затем связать DataContext на GenericView пункта ни к чему е lsewhere.

Однако, если вы собираетесь связывать другие значения VMFactory внешних по отношению к UserControl (т.е. <vw:GenericView VMFactory={Binding ...}"/>), то следует использовать RelativeSource с режимом FindAncestor для типа UserControl.

<!-- Shortened to show pertinent Binding --> 
<ctrl:CommandTextBox Command="{Binding VMFactory.CreateViewModelCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}"/> 
+0

Ваш второй пример похож на мою первоначальную попытку, которая не работала для меня, я попробовал еще раз и узнал, что она работает, но только если я не задаю свойства DataContext и VMFactory UserControl. Мысли? –

+0

DataContext имеет смысл, но не VMFactory.Вы пытались установить только VMFactory? – toadflakz

+0

Вот что я пытался передать, это работает, если я только устанавливаю VMFactory. Если я также установил DataContext, команда будет нарушена. –

0

Как @toadflakz сказал, что это очень распространенная проблема в WPF и тот, который мне потребовалось некоторое время, чтобы получить мою голову вокруг, когда я узнавал WPF. К счастью, решение прост. Предположим, что у нас есть UserControl, у которого есть объект DataContext, а другой - как значение DependencyProperty, которое объявлено в пределах UserControl ... вашей ситуации.

От вUserControl XAML, вы можете данные привязки к свойству объекта, заданного в качестве DataContext как обычно:

<TextBlock Text="{Binding PropertyFromDataContextObject}" /> 

Если вы хотите привязать данные к объекту из множества объектов, как значение DependencyProperty, вы можете просто использовать RelativeSource Binding:

<TextBlock Text="{Binding PropertyFromDependencyPropertyObject, RelativeSource={ 
    RelativeSource AncestorType={x:Type YourPrefix:YourUserControl}}}" /> 

Обратите внимание, что оба этих Binding с могут быть использованы togeth er в том же UserControl, если установлены оба свойства DataContext и DependencyProperty.

+0

Я понимаю привязку, но она не работает, как предлагается? DependencyProperty (VMFactory) кажется нулевым, если установлен DataContext? Если вы посмотрите на мой MainPage.xaml, вы увидите, что я создал два экземпляра GenericView для устранения неполадок, если я добавлю обработчик событий Loaded в UserControl, я вижу, что экземпляр с привязкой DataContext будет иметь нулевой VMFactory и не будет функционировать как и ожидалось. Хотя экземпляр без DataContext будет иметь объект VMFactory, и команда будет выполняться, как ожидалось. Мысли? –

+0

Он должен работать, если вы просто следуете моим примерам ... вы явно усложнили свой код. При доступе к свойствам из объекта DataContext вы не должны использовать «связывание с RelativeSource», поскольку это изменяет источник данных в «DataContext». Экспериментируйте в новом проекте. Кроме того, в окне вывода в Visual Studio должны быть ошибки «Binding», которые сообщают вам, в чем проблема. – Sheridan

+0

Я не использую RelativeSource для доступа к DataContext? Связывание TextBox обращается к DataContext, привязка команды обращается к VMFactory. Синтаксис для каждого из них идентичен вашему примеру? –

Смежные вопросы