【发布时间】:2014-11-05 08:58:44
【问题描述】:
我正在编写的代码实际上是一种 WPF 行为,用于从网格控件中获取所选项目(我们知道,SelectedItems 不是可绑定的属性)。我实际上使用的是 Telerik RadGridView,但我希望行为对于具有 SelectionChanged 事件的任何事物都是通用的。但是,不同的控件对 SelectionChanged 事件处理程序有不同的签名(RadGridView 使用 Telerik.Windows.Controls.SelectionChangeEventArgs,而标准 GridView 使用 System.Windows.Controls.SelectionChangedEventArgs)。我们可以确定的一件事是,事件 args 将从 EventArgs 派生(实际上我们可以确定它将从 RoutedEventArgs 派生)。
但是,虽然我可以编写一个将 RoutedEventArgs 作为其第二个参数的通用事件处理程序,并且我可以使用反射来获取 SelectionChangedEvent 的 EventInfo,但我无法在不使用精确签名的情况下将处理程序挂钩到事件对于事件处理程序 - 在本例中为 RadGridView 处理程序。
这是我的代码。我已经包含了所有这些,但重要的是 SelectItemPropertyChanged,它是 DependencyObject PropertyChangedCallback,它试图将事件处理程序 SelectionChangedHandler 连接到 SelectionChangedEvent。 (SelectionChangedHandler 中的代码与问题无关,但我已将其保留,因此很清楚我在做什么)。
public static class SelectedItemsChangedBehaviour{
public static readonly DependencyProperty SelectItemsProperty =
DependencyProperty.RegisterAttached("SelectItems", typeof(bool), typeof(SelectedItemsChangedBehaviour),
new FrameworkPropertyMetadata(false, new PropertyChangedCallback(SelectItemPropertyChanged)));
public static void SetSelectItems(DependencyObject dependencyObject, bool selectItems)
{
dependencyObject.SetValue(SelectItemsProperty, selectItems);
}
public static bool GetSelectItems(DependencyObject dependencyObject)
{
return (bool)dependencyObject.GetValue(SelectItemsProperty);
}
private static void SelectItemPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
// No common base for all classes with SelectionChanged event so use reflection
EventInfo selectionChangedEventInfo = dependencyObject.GetType().GetEvent("SelectionChanged");
if (selectionChangedEventInfo == null)
{
throw new ArgumentException("Must have a SelectionChanged event.");
}
if ((bool)dependencyPropertyChangedEventArgs.OldValue)
{
// This is what I want to do, but it throws because the handler signature is wrong
selectionChangedEventInfo.RemoveEventHandler(dependencyObject, (RoutedEventHandler)SelectionChangedHandler);
// This works fine because it is of the right type for the RadGridView but is not general
//selectionChangedEventInfo.RemoveEventHandler(dependencyObject, (EventHandler<Telerik.Windows.Controls.SelectionChangeEventArgs>)SelectionChangedHandler);
}
if ((bool)dependencyPropertyChangedEventArgs.NewValue)
{
// This is what I want to do, but it throws because the handler signature is wrong
selectionChangedEventInfo.AddEventHandler(dependencyObject, (RoutedEventHandler)SelectionChangedHandler);
// This works fine because it is of the right type for the RadGridView but is not general
//selectionChangedEventInfo.AddEventHandler(dependencyObject, (EventHandler<Telerik.Windows.Controls.SelectionChangeEventArgs>)SelectionChangedHandler);
}
}
private static void SelectionChangedHandler(object sender, RoutedEventArgs eventArgs)
{
// No common base for all classes with AddedItems/RemovedItems (eg. System.Windows.Controls.SelectionChangedEventArgs / Telerik.Windows.Controls.SelectionChangeEventArgs
PropertyInfo addedItemsInfo = eventArgs.GetType().GetProperty("AddedItems");
PropertyInfo removedItemsInfo = eventArgs.GetType().GetProperty("RemovedItems");
if (addedItemsInfo == null || removedItemsInfo == null)
{
throw new ArgumentException("Must have AddedItems and RemovedItems");
}
foreach (object item in (IEnumerable)addedItemsInfo.GetValue(eventArgs, null))
{
((ISelectable)item).IsSelected = true;
}
foreach (object item in (IEnumerable)removedItemsInfo.GetValue(eventArgs, null))
{
((ISelectable)item).IsSelected = false;
}
}
我已经尝试了各种方法来使用反射来为处理程序获取正确的签名,从而为正确的类型创建一个委托,但我无法让它工作 - AddEventHandler(和 RemoveEventHandler)抛出一个 InvalidArgumentException,完整的堆栈跟踪如下:
{"'System.Windows.RoutedEventHandler' 类型的对象无法转换为'System.EventHandler`1[Telerik.Windows.Controls.SelectionChangeEventArgs]' 类型。"}
at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfoculture, Boolean needsSpecialCast)
谁能给点建议?
【问题讨论】:
-
您说“它会抛出”——请您提供完整的堆栈跟踪信息吗? (或者如果它是一个编译时错误,那么给出确切的错误消息——在这种情况下“抛出”并不合适。)如果你可以将重要部分提取到一个简短但完整的程序中,它也会变得更容易- 它根本不需要是 WPF。
-
它抛出(如果是编译器错误,我不会说抛出:-))例外是:System.ArgumentException {“'System.Windows.RoutedEventHandler'类型的对象无法转换在 System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfoculture, Boolean needsSpecialCast) 处键入 'System.EventHandler`1[Telerik.Windows.Controls.SelectionChangeEventArgs]'."} 我会尝试将其放入程序中,但正如我所说,重要的是 SelectItemPropertyChanged
-
(如何在这些 cmets 中添加换行符???)
-
您不能,但您应该将详细信息编辑到问题中而不是 cmets。