C# WPF:在DataTemplate中绑定DependencyProperty。未激发PropertyChangedCallback
今天我的处境真的很艰难。由于缺乏WPF方面的经验,我无法理解。我开发了从类生成GUI的小框架(WinForms\WPF\HTML)。为此,我需要动态创建元素 我有带有DependencyProperty的自定义UserControlC# WPF:在DataTemplate中绑定DependencyProperty。未激发PropertyChangedCallback,c#,wpf,binding,C#,Wpf,Binding,今天我的处境真的很艰难。由于缺乏WPF方面的经验,我无法理解。我开发了从类生成GUI的小框架(WinForms\WPF\HTML)。为此,我需要动态创建元素 我有带有DependencyProperty的自定义UserControl public partial class ObjectPicker : UserControl { private ViewModel _vm; public ObjectPicker() {
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-wrapper具有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;
数据模板(例如,我放置了另外两个工作完美的模板):
当它起作用时
我不知道解决这个问题需要什么额外的信息。如果你需要更多,请留下评论,我再加上
更新1:添加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实现从传递的类型创建代理对象。我不确定是否理解此处的确切问题,但您可以尝试将ContentControl的Content属性设置为数据对象:
var content = new ContentControl();
content.ContentTemplate = (DataTemplate)cell.FindResource(TemplateName);
content.SetValue(ContentControl.ContentProperty, dataItem);
return content;
然后,您应该能够使用
{Binding Value}
绑定到DataTemplate中的Value属性。我澄清一下BindingObject这是一个对象包装器,它实现了INotifyPropertyChange接口。BindingObject类型具有属性值,我需要绑定该属性值。我可以将这个类添加到起始文章中,以获得更多的理解。这里的数据项是主对象的行。ObjectPickerDataTemplate—具有主对象的复杂类型属性的列。如何定义dataItem类以及ObjectPicker UserControl与此问题的关系如何?您正在GenerateElement方法中创建ContentControl,是吗?dataItem是来自GenerateElement方法参数的变量(受保护的覆盖FrameworkElement GenerateElement(DataGridCell,object dataItem)dataItem这里是SourceItems的对象)。然后dataItem的属性是一个复杂类型,然后我将ObjectPicker组件放在一个单元格中((DataTemplate)cell.FindResource(TemplateName);)我知道“dataItem”参数的来源,但如何定义源对象?ObjectPicker控件的XAML标记是什么样子的?如何从ObjectPicker控件设置source属性的值?请参阅main post。我更新了它。我在组件上没有任何XAML代码,我认为第一步是绑定到自定义属性。这是错误吗?
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; }
}
var content = new ContentControl();
content.ContentTemplate = (DataTemplate)cell.FindResource(TemplateName);
content.SetValue(ContentControl.ContentProperty, dataItem);
return content;