我刚尝试使用C ++ / CLI订阅WPF属性更改事件。我没想到这会变得困难。
首先,我尝试订阅某个窗口的特定属性(IsMouseDirectlyOver),最后成功使用以下代码:
void MyClass::DependencyPropertyChanged(Object^ sender, DependencyPropertyChangedEventArgs args)
{
Debug::WriteLine("DependencyPropertyChanged: "+sender->ToString()+", "+args.Property->Name);
}
window->IsMouseDirectlyOverChanged += gcnew DependencyPropertyChangedEventHandler(this, &MyClass::DependencyPropertyChanged);
然后我尝试订阅对象的任何属性更改(这对我来说最重要,因为我的最终代码必须能够通过属性名称处理属性更改)。我完全失败了。
我尝试过各种各样的东西但没有任何效果。我找不到任何C ++ / CLI示例,但根据文档和C#示例,以下似乎是最明智的代码:
window->PropertyChanged += gcnew PropertyChangedEventHandler(this, &MyClass::PropertyChanged);
void MyClass::PropertyChanged(Object^ sender, PropertyChangedEventArgs^ args)
{
...
}
但编译器通过错误C2039告诉我'PropertyChangedEvent'不是'System :: Windows :: Window'的元素。
我如何实现我的目标?
答案 0 :(得分:1)
评论中提及,您的代码无效,因为PropertyChanged
上没有Window
个事件,就像那个一样简单。
您可以执行的操作是覆盖Window
上的the OnPropertyChanged()
method。在您的覆盖中,您可以执行任何操作,包括提升PropertyChanged
(不要忘记先创建该事件)。
答案 1 :(得分:1)
类PropertyDescriptor(或派生的DependencyPropertyDescriptor)提供了一种通过AddValueChanged方法添加属性更改处理程序的机制:
DependencyPropertyDescriptor^ propertyDescriptor = DependencyPropertyDescriptor::FromName(
"ActualWidth", component->GetType(), component->GetType());
propertyDescriptor->AddValueChanged(component, gcnew EventHandler(ActualWidthChanged));
...
static void ActualWidthChanged(Object^ component, EventArgs^ e)
{
...
}
不幸的是处理程序没有传递更改的属性,所以我猜你必须为你要监视的所有属性添加不同的处理程序。
编辑:您可能会实现类似下面显示的代码,使用匿名委托将属性名称传递给适当的处理程序。但请注意,这是C#,据我所知,这不能在C ++ / CLI中完成,因为它不支持托管lambdas。 Mayby你可以在一个单独的程序集中包装一个这样的帮助器类,并从你的C ++ / CLI代码中使用它。
public delegate void PropertyChangedHandler(object component, string propertyName);
public static class DependencyPropertyDescriptorExt
{
public static void AddPropertyChangedHandler(
this object component, string propertyName, PropertyChangedHandler handler)
{
var propertyDescriptor = DependencyPropertyDescriptor.FromName(
propertyName, component.GetType(), component.GetType());
propertyDescriptor.AddValueChanged(component, (o, e) => handler(o, propertyName));
}
}
现在你可以编写和使用像这样的PropertyChangedHandler:
this.AddPropertyChangedHandler("ActualHeight", PropertyChanged);
...
private void PropertyChanged(object component, string propertyName)
{
...
}
答案 2 :(得分:1)
我看了一下窥探资料。我修改了它并写了一个非常非常基本的例子:
String^ ownerPropertyName = "IsActive";
DependencyObject^ propertyOwner = window;
DependencyPropertyDescriptor^ ownerPropertyDescriptor = DependencyPropertyDescriptor::FromName(ownerPropertyName, propertyOwner->GetType(), propertyOwner->GetType());
DependencyProperty^ ownerProperty = ownerPropertyDescriptor->DependencyProperty;
Type^ ownerPropertyType = ownerProperty->PropertyType;
DependencyProperty^ myProperty = DependencyProperty::Register(ownerPropertyName, ownerPropertyType, GetType(), gcnew PropertyMetadata(gcnew PropertyChangedCallback(&MyClass::BoundPropertyChangedCallback)));
Binding^ myPropertyToOwnerPropertyBinding = gcnew Binding(ownerPropertyName);
myPropertyToOwnerPropertyBinding->Mode = BindingMode::OneWay;
myPropertyToOwnerPropertyBinding->Source = propertyOwner;
BindingOperations::SetBinding(this, myProperty, myPropertyToOwnerPropertyBinding);
和
static void BoundPropertyChangedCallback(DependencyObject^ me, DependencyPropertyChangedEventArgs args)
{
Debug::WriteLine("BoundPropertyChangedCallback: "+args.OldValue+", "+args.NewValue+", "+args.Property->Name);
}
对我来说看起来很复杂。我不知道那些绑定的东西是否真的有必要。实际上,这甚至可以订阅没有事件的属性(如IsMouseOver),并且可以对未实现INotifyPropertyChanged的对象(如Window)进行操作。并且它不需要任何属性的开关/案例。