2015-05-27 4 views
1

У меня есть usercontrol, и для него есть набор Datacontext. Этот usercontrol также содержит свойство Dependency-Property. Теперь я хочу просто привязать это свойство.

Я думаю, что проблема имеет какое-то отношение к неправильному datacontext.Зависимость Свойство Datacontext

Зависимость-собственности в моем UserControl (называется TimePicker) выглядит следующим образом:

public TimeSpan Time 
    { 
     get { return (TimeSpan)GetValue(TimeProperty); } 
     set 
     { 
      SetValue(TimeProperty, value); 
      OnPropertyChanged(); 
     } 
    } 

    public static readonly DependencyProperty TimeProperty = DependencyProperty.Register("Time", typeof (TimeSpan), typeof (TimePicker)); 

Я стараюсь использовать его как это:

<upDownControlDevelopement:TimePicker Grid.Row="1" Time="{Binding Path=TimeValue}" /> 

Когда я делаю это я получаю следующее связывание ошибка:

System.Windows.Data Error: 40 : BindingExpression path error: 'TimeValue' property not found on 'object' ''TimePicker' (Name='TimePickerControl')'. BindingExpression:Path=TimeValue; DataItem='TimePicker' (Name='TimePickerControl'); target element is 'TimePicker' (Name='TimePickerControl'); target property is 'Time' (type 'TimeSpan') 

Любая помощь будет высоко оценен

Привет Майкл

PS: Вы можете загрузить код на here

+0

На что установлен DataContext? И можете ли вы опубликовать код для класса, для которого он установлен? – Bijington

+2

DataContext ваших элементов управления TimePicker, похоже, настроен на себя. Однако вам придется установить его в экземпляр модели представления, у которого есть свойство TimeValue, или вы установите явно источник привязки. – Clemens

+0

Если вы устанавливаете DataContext на это (то есть элемент управления TimePicker), вам необходимо изменить привязку к Time = "{Binding Path = Time}", если вы хотите привязать его к этому свойству, иначе, поскольку Clemens заявил, что вам нужно установите DataContext в экземпляр модели представления – Bijington

ответ

1

Вам не нужно переопределять контекст данных пользовательского элемента управления. Вы можете использовать RelativeSource, чтобы указать свойство источника привязки, то есть TimeValue, на любой другой источник, который вам нравится. . Если у вас есть свойство source в вашем классе Windows. Вы можете просто указать свою связывающую цель источника в контексте данных окна следующим образом: «Извинения для форматирования Вводимой с iPhone»

{Binding Path=DataContext.TimeValue, RelativeSource={ RelativeSource AncestorType={x:Type Window}}} 

+0

Спасибо большое! Это было именно то, что я ищу. –

+0

Не беспокойтесь, приятель. – ANewGuyInTown

1

Ваша ошибка гласит, что свойство «TIMEVALUE» не найден «объекта» «TimePicker», что означает, что WPF Framework ищет на объекте 'TimePicker' для разрешения значения свойства 'TimeValue'. Вы должны каким-то образом установить DataContextWindow или UserControl, который содержит объект 'TimePicker' экземпляру объекта 'TimePicker'.

Вместо этого он должен быть установлен в экземпляр класса, объявляющего свойство 'TimeValue'. Если вы используете модель представления, то вы должны установить его к экземпляру, что:

DataContext = new YourViewModel(); 

Если свойство 'TimeValue' объявлен в Window или UserControl, то вы можете установить DataContext к себе (хотя, как правило, не рекомендуется):

DataContext = this; 

Пожалуйста, обратите внимание, что при связывании данных в 'Time' собственности внутри вашего TimePicker управления, вы должны использовать RelativeSource Binding:

<TextBlock Text="{Binding Time, RelativeSource={RelativeSource 
    AncestorType={x:Type YourLocalPrefix:TimePicker}}}" ... /> 
+0

Точно в том месте, где я застрял. Когда вы смотрите на код (я отредактировал вопрос), вы можете увидеть проблему. Usercontol имеет свой собственный набор данных datacontext, и мне нужно переопределить его –

+0

Показать соответствующие части кода здесь (в вашем вопросе) – Sheridan

0

Обычно мы не ставим DataContext directly.If и хочет установить datacontext создает экземпляр вашего пользовательского контроля и устанавливает для каждого из них каждый день.

3

Хотя это было решено, похоже, некоторые, на мой взгляд, ненадлежащее использование DataContext.

При разработке пользовательского многоразового элемента управления вы не должны устанавливать DataContext. Что будет DataContext, то есть для пользователя пользователя элемента управления, чтобы решить, а не для разработчика. Рассмотрим следующую общую структуру кода:

<Grid DataContext="{Binding Data}"> 
    <TextBox Text="{Binding TextValue1}" /> 
    <!-- Some more controls --> 
</Grid> 

Обратите внимание, что здесь, вы с помощью элемента управления Grid. Разработчик элемента управления (в данном случае, команда WPF) вообще не касался DataContext - это зависит от вас. Что это значит для вас как разработчика контроля? Ваше определение DependencyProperty в порядке, но вы не должны касаться DataContext. Как вы тогда привяжете что-то внутри своего контроля к значению DependencyProperty? Хороший способ использует шаблон (пространства имен опущены):

<MyTimePicker> 
    <MyTimePicker.Template> 
     <ControlTemplate TargetType="MyTimePicker"> 
      <!-- Stuff in your control --> 
      <TextBlock Text="{TemplateBinding Time}" /> 
      <TextBox Text="{Binding Time, RelativeSource={RelativeSource TemplatedParent}}" /> 
     </ControlTemplate> 
    <MyTimePicker.Template> 
</MyTimePicker> 

Обратите внимание, что TemplateBinding всегда только в одну стороны, так что если вам нужно любое редактирование на всех, вы должны использовать нормальное связывание (как вы можете видеть на TextBox в примере).

Это означает, что TextBlock/Box внутри вашего элемента управления получит значение Time из собственного пользовательского элемента управления, игнорируя любой установленный вами DataContext.

Затем, когда вы используете контроль, вы делаете это так (добавлено к моему первому примеру):

<Grid DataContext="{Binding Data}"> 
    <TextBox Text="{Binding TextValue1}" /> 
    <!-- Some more controls --> 
    <MyTimePicker Time="{Binding TimeValue}" /> 
</Grid> 

Что произошло здесь в том, что MyTimePicker не DataContext установить в любом месте на всех - это получает его от родительского элемента управления (Grid). Таким образом, значение выглядит следующим образом: Data-->(binding)-->MyTimePicker.Time-->(template binding)-->TextBlock.Text.

И прежде всего, избежать этого в конструкторе пользовательского элемента управления:

public MyTimePicker() 
{ 
    InitializeComponent(); 
    DataContext = this; 
} 

Это отменит любые DataContext набора в XAML, который сделает связывание огромной боли (потому что вы должны всегда установить Source вручную). Предыдущий пример не будет работать, и это не будет работать либо:

<MyTimePicker DataContext="{Binding Data}" Time="{Binding TimeValue}" /> 

Вы думали бы, что это нормально, но DataContext будет решена в InitializeComponent() вызова, так что значение будет немедленно перезаписаны. Таким образом, привязка к TimeValue будет искать его в контроле вместо этого (что, конечно же, потерпит неудачу).

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

+0

Спасибо, много. Ты решил много проблем, которые у меня есть с моим пользовательским контролем. Я бы оценил тебя, но У меня еще нет этой привилегии :-) –

+0

Рад, что я мог бы помочь, продолжайте хорошую работу! – vesan