2017-01-18 13 views
0

今日私は本当に難しい状況です。 WPFでの経験不足のために私は理解できません。私はクラスからGUI生成(WinForms \ WPF \ HTML)の小さなフレームワークを開発します。このためには、要素を動的に作成する必要があります。WPF:DataTemplateのDependencyPropertyをバインドします。 PropertyChangedCallbackが起動しません

私がした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; 
     } 
    } 

でカスタムユーザーコントロールを持っている私はGenerateElement法(BindingObject - 2つの特性値とPROPNAMEとラッパー)をオーバーライドCustomBoundColumnを有しています。それから、私はこのようなオブジェクトをバインドし、それは動作しません。それが動作するとき

objectPicker.SetBinding(ObjectPicker.ObjectValueProperty, binding); 

<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> 

私はこのようなプログラムでバインディング:

 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; 

データテンプレート(例えば私は完璧な仕事2つの別のテンプレートを置きます)。

この問題を解決するために必要な追加情報はありません。もっと必要な場合は、コメントを残して追加します。

UPDATE1:

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)); 
    } 
} 

をBindingObjectクラスを追加するアップデート2:実行時にデータ項目

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

私はここにあなたの正確な問題を理解するかどうかわからないですが、あなたは、データオブジェクトにContentControlにのContentプロパティを設定しようとすることができます:

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

が次にあなたがValueプロパティにバインドすることができるはずです{Binding Value}を使用しているDataTemplateで

+0

私はこの瞬間を明確にします。BindingObjectこれはINotifyPropertyChangeインターフェイスを実現するオブジェクトラッパーです。 BindingObject型にはValueというプロパティがあり、バインディングが必要です。このクラスを開始ポストに追加して、より理解しやすくできます。 PS。 dataItemここはメインオブジェクトの行です。 ObjectPickerDataTemplate - 主オブジェクトの複合型プロパティを持つ列。 – CMaker

+0

dataItemクラスはどのように定義されていますか?また、この問題に関連するObjectPicker UserControlはどのようになっていますか? GenerateElementメソッドでContentControlを作成していますか? – mm8

+0

dataItemは、GenerateElementメソッドのパラメータからの変数です。protected override FrameworkElement GenerateElement(DataGridCell cell、object dataItem)ここでdataItemはSourceItemsのオブジェクトです。次に、dataItemのプロパティが複雑な型である場合、ObjectPickerコンポーネントをセル((DataTemplate)cell.FindResource(TemplateName);)に配置します。 – CMaker

関連する問題