将 class 与它继承的接口(通过 Foo 是 IBar)进行比较 returns false:为什么?
Comparing class to Interface it inherits ( via Foo is IBar ) returns false : Why?
我想要完成的事情
我希望能够将事件处理程序从一个 class 绑定到 XAML 中另一个 class 中对象按钮的 Click
事件该控件的:
例如:
<Button Click="{OtherClass.EventHandler}"/>
我的方法
我正在使用来自 here
的近十年前的代码
我正在使用 class 继承 System.Windows.Input.ICommand
接口,该接口基本上包装了 Action
以减少我的生活...愚蠢:
public class Command : ICommand {
private Action _ToExecute;
public Action ToExecute{
get{ return this._ToExecute; }
set{ this._ToExecute = value; }
}
public Command( Action ToExecute ){ this._ToExecute = ToExecute; }
public event EventHandler CanExecuteChanged; //Never Used
public bool CanExecute( object parameter ){ return true; }
public void Execute( object parameter ){
this._ToExecute?.Invoke( );
}
}
我在下面的 class 中使用这个 class 它扩展了按钮的行为,使我能够将按钮的 Click
事件处理程序绑定到这些命令:
public static class ButtonClickBehavior{
public static ReadOnly DependencyProperty[] Properties =
EventBehviourFactory.CreateCommandExecutionEventBehaviour(
ButtonBase.ClickEvent, new string[]{ "Command", "Parameter" },
typeof( ButtonClickBehavior ) );
public static void SetCommand( DependencyObject o, ICommand value ){
o.SetValue( Properties[ 0 ], value );
}
public static ICommand GetCommand( DependencyObject o ){
return o.GetValue( Properties[ 0 ] as ICommand;
}
public static void SetParameter( DependencyObject o, object value ){
o.SetValue( Properties[ 1 ], value );
}
public static object GetParameter( DependencyObject o ){
return o.GetValue( Properties[ 1 ] );
}
}
这个 class 使用了前面提到的静态 class :(主要基于从上面引用的源代码中大量提取的代码)
public static class EventBehaviorFactory {
public static DependencyProperty[] CreateCommandExecutionEventBehaviour(
RoutedEvent routedEvent, string[] propertyNames, Type ownerType ){
ExecuteCommandOnRoutedEventBehaviour
CommandExecutor = new ExecuteCommandOunRoutedBehavior( routedEvent );
DependencyProperty p = DependencyProperty.RegisterAttached(
propertyNames[ 0 ], typeof( ICommand ), ownerType,
new PropertyMetadata( null, CommandExecutor.PropertyChanged ) );
if ( propertyNames.Count( ) > 1 )
return new DependencyProperty[ ]{
p, DependencyProperty.RegisterAttached(
propertyNames[ 1 ], typeof( ICommand ), ownerType,
new PropertyMetadata( null, CommandExecutor.PropertyChanged ) )
};
else return new DependencyProperty[ ] { p };
}
private class ExecuteCommandOnRoutedEventBehaviour : ExecuteCommandBehaviour {
private readonly RoutedEvent _routedEvent;
public ExecuteCommandOnRoutedEventBehaviour( RoutedEvent routedEvent ){
this._routedEvent = routedEvent;
}
protected override void AdjustEventHandlers(
DependencyObject sender, object oldValue, object newValue ){
UIElement element = sender as UIElement;
if ( oldValue != null )
element.RemoveHandler(
_routedEvent, new RoutedEventHandler( EventHandler );
if ( newValue != null )
element.AddHandler(
_routedEvent, new RoutedEventHandler( EventHandler );
}
protected void EventHandler( object sender, RoutedEventArgs e ){
HandleEvent( sender, e );
}
}
internal abstract class ExecuteCommandBehaviour{
protected DependencyProperty
_commandProperty, _paramProperty;
protected abstract void AdjustEventHandler(
DependencyObject sender, object oldValue, object newValue );
protected void HandleEvent( object sender, EventArgs e ){
DependencyObject dp = sender as DependencyObject;
if ( dp == null )
return;
ICommand cmd = dp.GetValue( _commandProperty ) as ICommand;
if ( command == null )
return;
object param
if ( this._paramProperty == null || (
param = dp.GetValue( this._paramProperty ) ) == null ){
if ( cmd.CanExecute( e ) )
cmd.Execute( e );
} else {
if ( cmd.CanExecute( param ) )
cmd.Execute( param );
}
}
public void PropertyChanged(
DependencyObject sender, DependencyPropertyChangedEventArgs e ) {
/*THIS IS THE LINE GIVING ME TROUBLE.*/
if ( e.Property.PropertyType is ICommand ){
//DO STUFF
} else if ( /*Something ELSE*/ )
//DO SOMETHING ELSE
}
}
}
我意识到我正在使用的代码来自一个已有近十年历史的源代码并且应该存在某个地方应该能够做我想做的事情但是对于我所有的 google 搜索我想出了空(除了那个我一直在打这个结果所以我想无论如何,我会修改它以满足我的需要并滚动它)。如果有人有更好的方法来完成我想做的事情,我完全赞成(再次,我希望能够在 XAML、[=47= 中进行实际绑定]不在后面的代码中)
我的问题
问题是我的类型比较失败了(即使在我观看调试时我也看到 PropertyType 是 ICommand 类型)。当我使用 is
关键字时,与 ICommand 相比的 PropertyType 总是 returns false,并且 Linq 魔法的任何尝试(例如 e.Property.PropertyType.GetInterfaces( ).Any( i => i.IsGenericType && i.GetGenericTypeDefinition( ) == typeof( ICommand ) )
)也会失败。
因此,如果有人有更好的方法,我会洗耳恭听,但现在 - 为什么我的类型比较失败如此严重?
e.PropertyType
是 Type
,不是该类型的实例,因此无法与 "is" 进行比较。你需要的是(举例):
typeof(ICommand).IsAssignableFrom(e.Property.PropertyType)
我想要完成的事情
我希望能够将事件处理程序从一个 class 绑定到 XAML 中另一个 class 中对象按钮的 Click
事件该控件的:
例如:
<Button Click="{OtherClass.EventHandler}"/>
我的方法
我正在使用来自 here
的近十年前的代码我正在使用 class 继承 System.Windows.Input.ICommand
接口,该接口基本上包装了 Action
以减少我的生活...愚蠢:
public class Command : ICommand {
private Action _ToExecute;
public Action ToExecute{
get{ return this._ToExecute; }
set{ this._ToExecute = value; }
}
public Command( Action ToExecute ){ this._ToExecute = ToExecute; }
public event EventHandler CanExecuteChanged; //Never Used
public bool CanExecute( object parameter ){ return true; }
public void Execute( object parameter ){
this._ToExecute?.Invoke( );
}
}
我在下面的 class 中使用这个 class 它扩展了按钮的行为,使我能够将按钮的 Click
事件处理程序绑定到这些命令:
public static class ButtonClickBehavior{
public static ReadOnly DependencyProperty[] Properties =
EventBehviourFactory.CreateCommandExecutionEventBehaviour(
ButtonBase.ClickEvent, new string[]{ "Command", "Parameter" },
typeof( ButtonClickBehavior ) );
public static void SetCommand( DependencyObject o, ICommand value ){
o.SetValue( Properties[ 0 ], value );
}
public static ICommand GetCommand( DependencyObject o ){
return o.GetValue( Properties[ 0 ] as ICommand;
}
public static void SetParameter( DependencyObject o, object value ){
o.SetValue( Properties[ 1 ], value );
}
public static object GetParameter( DependencyObject o ){
return o.GetValue( Properties[ 1 ] );
}
}
这个 class 使用了前面提到的静态 class :(主要基于从上面引用的源代码中大量提取的代码)
public static class EventBehaviorFactory {
public static DependencyProperty[] CreateCommandExecutionEventBehaviour(
RoutedEvent routedEvent, string[] propertyNames, Type ownerType ){
ExecuteCommandOnRoutedEventBehaviour
CommandExecutor = new ExecuteCommandOunRoutedBehavior( routedEvent );
DependencyProperty p = DependencyProperty.RegisterAttached(
propertyNames[ 0 ], typeof( ICommand ), ownerType,
new PropertyMetadata( null, CommandExecutor.PropertyChanged ) );
if ( propertyNames.Count( ) > 1 )
return new DependencyProperty[ ]{
p, DependencyProperty.RegisterAttached(
propertyNames[ 1 ], typeof( ICommand ), ownerType,
new PropertyMetadata( null, CommandExecutor.PropertyChanged ) )
};
else return new DependencyProperty[ ] { p };
}
private class ExecuteCommandOnRoutedEventBehaviour : ExecuteCommandBehaviour {
private readonly RoutedEvent _routedEvent;
public ExecuteCommandOnRoutedEventBehaviour( RoutedEvent routedEvent ){
this._routedEvent = routedEvent;
}
protected override void AdjustEventHandlers(
DependencyObject sender, object oldValue, object newValue ){
UIElement element = sender as UIElement;
if ( oldValue != null )
element.RemoveHandler(
_routedEvent, new RoutedEventHandler( EventHandler );
if ( newValue != null )
element.AddHandler(
_routedEvent, new RoutedEventHandler( EventHandler );
}
protected void EventHandler( object sender, RoutedEventArgs e ){
HandleEvent( sender, e );
}
}
internal abstract class ExecuteCommandBehaviour{
protected DependencyProperty
_commandProperty, _paramProperty;
protected abstract void AdjustEventHandler(
DependencyObject sender, object oldValue, object newValue );
protected void HandleEvent( object sender, EventArgs e ){
DependencyObject dp = sender as DependencyObject;
if ( dp == null )
return;
ICommand cmd = dp.GetValue( _commandProperty ) as ICommand;
if ( command == null )
return;
object param
if ( this._paramProperty == null || (
param = dp.GetValue( this._paramProperty ) ) == null ){
if ( cmd.CanExecute( e ) )
cmd.Execute( e );
} else {
if ( cmd.CanExecute( param ) )
cmd.Execute( param );
}
}
public void PropertyChanged(
DependencyObject sender, DependencyPropertyChangedEventArgs e ) {
/*THIS IS THE LINE GIVING ME TROUBLE.*/
if ( e.Property.PropertyType is ICommand ){
//DO STUFF
} else if ( /*Something ELSE*/ )
//DO SOMETHING ELSE
}
}
}
我意识到我正在使用的代码来自一个已有近十年历史的源代码并且应该存在某个地方应该能够做我想做的事情但是对于我所有的 google 搜索我想出了空(除了那个我一直在打这个结果所以我想无论如何,我会修改它以满足我的需要并滚动它)。如果有人有更好的方法来完成我想做的事情,我完全赞成(再次,我希望能够在 XAML、[=47= 中进行实际绑定]不在后面的代码中)
我的问题
问题是我的类型比较失败了(即使在我观看调试时我也看到 PropertyType 是 ICommand 类型)。当我使用 is
关键字时,与 ICommand 相比的 PropertyType 总是 returns false,并且 Linq 魔法的任何尝试(例如 e.Property.PropertyType.GetInterfaces( ).Any( i => i.IsGenericType && i.GetGenericTypeDefinition( ) == typeof( ICommand ) )
)也会失败。
因此,如果有人有更好的方法,我会洗耳恭听,但现在 - 为什么我的类型比较失败如此严重?
e.PropertyType
是 Type
,不是该类型的实例,因此无法与 "is" 进行比较。你需要的是(举例):
typeof(ICommand).IsAssignableFrom(e.Property.PropertyType)