今天我真的很難受。由於缺乏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的創建代理對象的實現示例實現。
我澄清了這一刻BindingObject這是一個對象包裝器,它實現了INotifyPropertyChange接口。 BindingObject類型的屬性值,我需要綁定。我可以將此課程添加到啓動帖子中以獲得更多理解。 PS。這裏的dataItem是主對象的行。 ObjectPickerDataTemplate - 具有主對象的複雜類型屬性的列。 – CMaker
dataItem類是如何定義的以及ObjectPicker UserControl如何與此問題相關?您正在GenerateElement方法中創建一個ContentControl,是嗎? – mm8
dataItem是一個來自GenerateElement方法參數的變量(protected override FrameworkElement GenerateElement(DataGridCell cell,object dataItem)這裏的dataItem是SourceItems的一個對象)。然後我把ObjectPicker組件放入一個單元格((DataTemplate)cell.FindResource(TemplateName);) – CMaker