代码之家  ›  专栏  ›  技术社区  ›  CodeHulk

ICommandSource和DelegateCommand

  •  1
  • CodeHulk  · 技术社区  · 10 年前

    我正在尝试使用一些命令创建用户控件。如果我使用这里显示的方法连接xaml中的命令 http://msdn.microsoft.com/en-us/library/vstudio/ms771361(v=vs.90).aspx 它可以工作,但如果我使用Prism库中的DelegateCommand,CanExecuteChanged不会在用户控件上启动,我无法找出原因。我很抱歉,我意识到这是很多代码。正确执行激发,但CanExecute从不执行。

    提前感谢。

    自定义控件Xaml

    <UserControl x:Class="Controls.LinkButton"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <TextBlock>
            <Hyperlink x:Name="hyperLink" Click="Hyperlink_Click">
                <Run x:Name="textRun"
                     Text="Click Me"/>
            </Hyperlink>
        </TextBlock>
    </UserControl>
    

    自定义控制代码后面

    public partial class LinkButton : UserControl, ICommandSource
    {
        public LinkButton()
            : base()
        {
            InitializeComponent();
            textRun.DataContext = this;
            hyperLink.DataContext = this;
        }
    
        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }
    
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(LinkButton), new PropertyMetadata(null, new PropertyChangedCallback(CommandChanged)));
    
        public object CommandParameter
        {
            get { return (object)GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }
    
        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.Register("CommandParameter", typeof(object), typeof(LinkButton), new PropertyMetadata(null));
    
        public IInputElement CommandTarget
        {
            get { return (IInputElement)GetValue(CommandTargetProperty); }
            set { SetValue(CommandTargetProperty, value); }
        }
    
        public static readonly DependencyProperty CommandTargetProperty =
            DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(LinkButton), new PropertyMetadata(null));
    
        private void Hyperlink_Click(object sender, RoutedEventArgs e)
        {
            if (Command != null)
            {
                RoutedCommand command = Command as RoutedCommand;
    
                if (command != null)
                {
                    command.Execute(CommandParameter, CommandTarget);
                }
                else
                {
                    ((ICommand)Command).Execute(CommandParameter);
                }
            }
        }
    
        public static EventHandler canExecuteChangedHandler;
    
        private static void CommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            LinkButton lb = (LinkButton)d;
            lb.HookUpCommand((ICommand)e.OldValue, (ICommand)e.NewValue);
        }
    
        // Add a new command to the Command Property. 
        private void HookUpCommand(ICommand oldCommand, ICommand newCommand)
        {
            // If oldCommand is not null, then we need to remove the handlers. 
            if (oldCommand != null)
            {
                RemoveCommand(oldCommand, newCommand);
            }
            AddCommand(oldCommand, newCommand);
        }
    
        // Remove an old command from the Command Property. 
        private void RemoveCommand(ICommand oldCommand, ICommand newCommand)
        {
            EventHandler handler = CanExecuteChanged;
            oldCommand.CanExecuteChanged -= handler;
        }
    
        // Add the command. 
        private void AddCommand(ICommand oldCommand, ICommand newCommand)
        {
            EventHandler handler = new EventHandler(CanExecuteChanged);
            canExecuteChangedHandler = handler;
            if (newCommand != null)
            {
                newCommand.CanExecuteChanged += canExecuteChangedHandler;
            }
        }
    
        private void CanExecuteChanged(object sender, EventArgs e)
        {
            if (this.Command != null)
            {
                RoutedCommand command = this.Command as RoutedCommand;
    
                // If a RoutedCommand. 
                if (command != null)
                {
                    if (command.CanExecute(CommandParameter, CommandTarget))
                    {
                        this.IsEnabled = true;
                    }
                    else
                    {
                        this.IsEnabled = false;
                    }
                }
                // If a not RoutedCommand. 
                else
                {
                    if (Command.CanExecute(CommandParameter))
                    {
                        this.IsEnabled = true;
                    }
                    else
                    {
                        this.IsEnabled = false;
                    }
                }
            }
        }
    }
    

    <ctrl:LinkButton Command="{Binding LinkClicked}"/>
    
    
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            LinkClicked = new DelegateCommand(DoSomething, CanDoSomething);
    
            InitializeComponent();
            DataContext = this;
            LinkClicked.RaiseCanExecuteChanged();
        }
    
        public DelegateCommand LinkClicked { get; set; }
    
        public void DoSomething()
        {
            MessageBox.Show("Did Something");
        }
    
        public bool CanDoSomething()
        {
            return false;
        }
    }
    
    1 回复  |  直到 10 年前
        1
  •  1
  •   yo chauhan    10 年前

    这里的问题是您正在调用LinkClicked.RiseCanExecuteChanged();在设置DataContext之后立即绑定LinkedCommand,因此DelegateCommand的CanExecuteChanged事件为空,因此RaiseCanExecuteChange()不会执行任何操作。因此避免在Window的加载事件中调用LinkClicked.RiseCanExecuteChanged(),因为在此之前绑定将被更新。尽管这是一个肮脏的解决方案,因为您必须在任何地方使用此LinkButton并绑定其命令。

    RaiseCanExecuteChanged的实现如下

        public void RaiseCanExecuteChanged()
        {
            if (CanExecuteChanged != null)  //CanExecuteChanged is coming null in your case so the event is not fired.
                CanExecuteChanged(this, new EventArgs()); 
        }
    

    或者更好的解决方案是,您没有在AddCommand方法中调用CanExecute,在实际的命令实现中,CanExecute被调用

    if (newCommand != null)
            {
                newCommand.CanExecuteChanged += CanExecuteChanged;
                newCommand.CanExecute(CommandParameter); //you are missing this.
            }
    

    如果这样做,则无需调用RaiseCanExecuteChanged。