2009-04-22 2 views
6

Я пытаюсь связать текстовое свойство TextBlock очень динамичным способом. Мне нужно получить Путь от базового объекта.Как связать свойство Binding.Path с базовыми данными?

Вот DataTemplate:

<DataTemplate DataType={x:Type local:DummyClass}> 
    <TextBlock Text={Binding Path=???} /> 
</DataTemplate> 

Объект DummyClass имеет свойство с именем «FieldValuePath» - путь, который нужно положить где ??? является.

Идея заключается в том, что шаблон данных должен быть графическим интерфейсом для просмотра/редактирования любого свойства любого объекта. Поэтому предпочтительнее объявить XAML, который привяжет некоторые элементы управления (текстовые поля, текстовые блоки, датпикеры и т. Д.) К заданному свойству.

Возможно, у кого-нибудь есть предложения о том, как реализовать такую ​​вещь?

ответ

7

Если вы создаете привязку в коде позади, вы можете заставить его работать. Например, простой код, генерируемый связывание:

Binding binding = new Binding("BindingPath"); 
binding.Mode = BindingMode.TwoWay; 
BindingOperations.SetBinding(textBoxName, TextBox.TextProperty, binding); 

Поскольку путь в этом связывания («BindingPath») это просто строка, эта строка может исходить из любого доступного объекта.

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


Другая возможность на основе ваших комментариев:

This blog post описывает способ создания пользовательского связывания класса, унаследовав от MarkupExtension. Возможно, вы сможете использовать это как отправную точку, чтобы включить мое предложение в многоразовую разметку xaml для вашего специального случая привязки.


Больше мысли:

Ладно, это была интересная проблема, поэтому я решил потратить немного времени, видя, если я мог придумать с рабочим раствором. Я заранее извиняюсь за длину следующих образцов кода ...

Базируясь мое решение на блоге я связан выше I создал этот класс:

public class IndirectBinder : MarkupExtension 
    { 
     public string IndirectProperty { get; set; } 

     public override object ProvideValue(IServiceProvider serviceProvider) 
     { 
      //try to get bound items for our custom work 
      DependencyObject targetObject; 
      DependencyProperty targetProperty; 
      bool status = TryGetTargetItems(serviceProvider, out targetObject, out targetProperty); 

      if (status) 
      { 
       Control targetControl = targetObject as Control; 
       if (targetControl == null) return null; 

       //Find the object to take the binding from 
       object dataContext = targetControl.DataContext; 
       if (dataContext == null) return null; 

       //Reflect out the indirect property and get the value 
       PropertyInfo pi = dataContext.GetType().GetProperty(IndirectProperty); 
       if (pi == null) return null; 

       string realProperty = pi.GetValue(dataContext, null) as string; 
       if (realProperty == null) return null; 

       //Create the binding against the inner property 
       Binding binding = new Binding(realProperty); 
       binding.Mode = BindingMode.TwoWay; 
       BindingOperations.SetBinding(targetObject, targetProperty, binding); 

       //Return the initial value of the binding 
       PropertyInfo realPi = dataContext.GetType().GetProperty(realProperty); 
       if (realPi == null) return null; 

       return realPi.GetValue(dataContext, null); 

      } 

      return null; 

     } 

     protected virtual bool TryGetTargetItems(IServiceProvider provider, out DependencyObject target, out DependencyProperty dp) 
     { 
      target = null; 
      dp = null; 
      if (provider == null) return false; 

      //create a binding and assign it to the target 
      IProvideValueTarget service = (IProvideValueTarget)provider.GetService(typeof(IProvideValueTarget)); 
      if (service == null) return false; 

      //we need dependency objects/properties 
      target = service.TargetObject as DependencyObject; 
      dp = service.TargetProperty as DependencyProperty; 
      return target != null && dp != null; 
     } 

Вы можете использовать эту новую разметку с следующий XAML:

<TextBox Text="{local:IndirectBinder IndirectProperty=FieldValuePath}"/> 

Где TextBox может быть любой класс, который наследуется от контроля и текста может быть любое свойство зависимостей.

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

Хотя это сложное решение, одно преимущество, которое он использует при использовании конвертера, заключается в том, что привязка, которая, наконец, создана, противоречит фактическому внутреннему свойству, а не объекту. Это означает, что он правильно реагирует на события PropertyChanged.

+0

ну, это подход, который может работать, но мне бы очень хотелось иметь возможность создавать привязки в XAML, потому что я планирую писать, имеют разные свойства привязки в зависимости от состояния базовых данных. Но, возможно, я действительно мог бы попытаться написать всю эту логику в коде ... – arconaut

+0

и, кроме того, это не только TextBlock, что я планирую указать привязку. Он должен быть редактором/зрителем для любого свойства на любом объекте. Я думаю, что я должен добавить в топ-пост. – arconaut

+0

спасибо за ответ, и спасибо за ссылку. Я собираюсь попробовать это – arconaut

-1
<DataTemplate DataType={x:Type local:DummyClass}> 
    <TextBlock Text={Binding Path=FieldValuePath} /> 
</DataTemplate> 

Должно быть правильное решение.Если вы слушаете изменения в FieldValuePath, вам необходимо убедиться, что DummyClass наследуется от INotifyPropertyChanged и что событие с измененным свойством запускается при изменении FieldValuePath.

+0

извините, но это установит текст равным значению FieldValuePath. Итак, если у вас есть dummyObject.FieldValuePath == "Property1", вы получите TextBlock.Text == "Property1" – arconaut

+0

В этом случае все ваши свойства объявлены как DependencyProperties? Вы должны иметь возможность привязываться к свойству property, если это так. Это может помочь ... http://geekswithblogs.net/thibbard/archive/2008/04/22/wpf-custom-control-dependency-property-gotcha.aspx –

2

Я бы рекомендовал использовать преобразователь:

<DataTemplate DataType={x:Type local:DummyClass}> 
    <TextBlock Text={Binding Converter={StaticResource PropertyNameToValueConverter, ConverterParameter=FieldValuePath}} /> 
</DataTemplate> 

Преобразователь получит класс и имя свойства, а оттуда он будет возвращать значение с помощью отражения.

+0

Но он вернет его только один раз. – arconaut

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