2017-01-18 55 views
0

今天我真的很難受。由於缺乏WPF經驗,我無法想象。我從類開發GUI生成的小框架(WinForms \ WPF \ HTML)。爲此,我需要動態創建元素。WPF:在DataTemplate中綁定依賴屬性。 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; 
     } 
    } 

我有CustomBoundColumn其中I重寫GenerateElement方法(其中BindingObject - 包裝用2個屬性值和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

我不知道如果我理解您的具體問題,在這裏,但你可以嘗試到ContentControl中的內容屬性設置爲數據對象:

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

那麼你應該能夠綁定到Value屬性在DataTemplate中使用{Binding Value}

+0

我澄清了這一刻BindingObject這是一個對象包裝器,它實現了INotifyPropertyChange接口。 BindingObject類型的屬性值,我需要綁定。我可以將此課程添加到啓動帖子中以獲得更多理解。 PS。這裏的dataItem是主對象的行。 ObjectPickerDataTemplate - 具有主對象的複雜類型屬性的列。 – CMaker

+0

dataItem類是如何定義的以及ObjectPicker UserControl如何與此問題相關?您正在GenerateElement方法中創建一個ContentControl,是嗎? – mm8

+0

dataItem是一個來自GenerateElement方法參數的變量(protected override FrameworkElement GenerateElement(DataGridCell cell,object dataItem)這裏的dataItem是SourceItems的一個對象)。然後我把ObjectPicker組件放入一個單元格((DataTemplate)cell.FindResource(TemplateName);) – CMaker