2017-01-18 4 views
0

Сегодня у меня действительно тяжелая ситуация. Я не могу понять из-за отсутствия опыта работы с WPF. Я разрабатываю небольшие рамки для генерации графического пользовательского интерфейса (WinForms \ WPF \ HTML) из класса. Для этого мне нужно динамически создавать элементы.WPF: привязка DependencyProperty в DataTemplate. PropertyChangedCallback не уволен

У меня есть пользовательское UserControl с DependencyProperty

public partial class ObjectPicker : UserControl 
    { 
     private ViewModel _vm; 
     public ObjectPicker() 
     { 
      InitializeComponent(); 
     } 

     public object ObjectValue 
     { 
      get { return GetValue(ObjectValueProperty); } 
      set { SetValue(ObjectValueProperty, value); } 
     } 

     public static DependencyProperty ObjectValueProperty = 
      DependencyProperty.Register(
       "ObjectValue", 
       typeof(object), 
       typeof(ObjectPicker), 
       new FrameworkPropertyMetadata(
        new PropertyMetadata(new object(), OnObjectChangeNotify, CoerceValueCallback), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); 

     private static void OnObjectChangeNotify(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      var sender = d as ObjectPicker; 
      sender.OnObjectValueChange(d, e); 
     } 

     public void OnObjectValueChange(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      this.ObjectValue = e.NewValue; 
     } 
    } 

У меня CustomBoundColumn где я переопределить метод GenerateElement (где BindingObject - обертка с 2-мя свойства Value и PROPNAME). Затем я связываю объект таким образом, а затем он не работает.

 var content = new ContentControl(); 
     content.ContentTemplate = (DataTemplate)cell.FindResource(TemplateName); 
     var propName = ((Binding)Binding).Path.Path; 
     BindingObject bo = new BindingObject(propName, dataItem); 
     content.SetValue(ContentControl.ContentProperty, bo); 
     return content; 

шаблон данных (например, я поставил две другие шаблоны, которые работают идеально):

<DataTemplate x:Key="TextBoxDataTemplate"> 
     <TextBox Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
    </DataTemplate> 
    <DataTemplate x:Key="DatePickerDataTemplate"> 
     <DatePicker SelectedDate="{Binding Value,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
    </DataTemplate> 
    <DataTemplate x:Key="ObjectPickerDataTemplate"> 
     <local:ObjectPicker ObjectValue="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 
    </DataTemplate> 

Когда я обязывающие программно, как это:

objectPicker.SetBinding(ObjectPicker.ObjectValueProperty, binding); 

Когда он работает.

Я не знаю, какая дополнительная информация необходима для решения этого вопроса. Если вам нужно больше оставить комментарий, я добавлю его.

Update1: добавить класс BindingObject

public class BindingObject : INotifyPropertyChanged 
{ 
    private object _value; 
    private PropertyDescriptor _pd; 
    private MethodInfo _method; 

    public BindingObject(string propName, object value) 
    { 
     _method = value.GetType().GetMethods().FirstOrDefault(x => x.Name == "OnPropertyChanged"); 
     if (!(value is INotifyPropertyChanged) || _method == null) throw new Exception("Invalid value"); 
     _value = value; 
     _pd = TypeDescriptor.GetProperties(_value.GetType())[propName]; 

     (_value as INotifyPropertyChanged).PropertyChanged += (o, e) => 
     { 
      OnPropertyChanged(nameof(Value)); 
      OnPropertyChanged(_pd.Name); 
     }; 
    } 

    public string PropName 
    { 
     get { return _pd.Name; } 
    } 

    public object Value 
    { 
     get 
     { 
      return _pd.GetValue(_value); 
     } 
     set 
     { 
      _pd.SetValue(_value, value); 

     } 
    } 

    private void RaisePropertyChanged() 
    { 
     _method.Invoke(_value, new[] { nameof(Value) }); 
     _method.Invoke(_value, new[] { _pd.Name }); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    [NotifyPropertyChangedInvocator] 
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

UPDATE2: пример Реализация DataItem

public class DataItem 
{ 
     public virtual string Value1 { get; set; } // This type of property work fine and binding 
     public virtual int Value2 { get; set; } // This type of property work fine and binding 
     public virtual DateTime Value3 { get; set; } // This type of property work fine and binding 
     public virtual ExampleComplexObject Object { get; set; } // This type not working 

} 

public class ExampleComplexObject 
{ 
     public virtual int Value1 { get; set; } 
     public virtual string Value2 { get; set; } 
} 

Во время выполнения, то нужно создать тип объекта пропуск на завод, где создать прокси-объект из пропускаемого типа с INotifyPropertyChanged реализация.

ответ

0

Я не уверен, если я понимаю ваш точный вопрос здесь, но вы могли бы попытаться установить Content свойство ContentControl к объекту данных:

var content = new ContentControl(); 
content.ContentTemplate = (DataTemplate)cell.FindResource(TemplateName); 
content.SetValue(ContentControl.ContentProperty, dataItem); 
return content; 

Тогда вы должны быть в состоянии связать свойству Value в DataTemplate (s) с использованием {Binding Value}.

+0

Я проясняю этот момент BindingObject это обертка объекта, которая реализует интерфейс INotifyPropertyChange. Тип BindingObject имеет свойство Value, которое мне нужно привязать. Я могу добавить этот класс в начальный пост для большего понимания. PS. dataItem вот строка основного объекта. ObjectPickerDataTemplate - столбец со сложным типом свойства основного объекта. – CMaker

+0

Как определяется класс dataItem и как ObjectPicker UserControl связан с этой проблемой? Вы создаете ContentControl в методе GenerateElement, не так ли? – mm8

+0

dataItem - это переменная из параметров метода GenerateElement (protected override FrameworkElement GenerateElement (ячейка DataGridCell, объект dataItem объекта), здесь объект объекта SourceItems). Тогда свойство dataItem является сложным типом, затем я помещаю компонент ObjectPicker в ячейку ((DataTemplate) cell.FindResource (TemplateName);) – CMaker

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