1

いくつかのコマンドでユーザーコントロールを作成しようとしています。ここに示すアプローチを使用して xaml でコマンドを接続するとhttp://msdn.microsoft.com/en-us/library/vstudio/ms771361(v=vs.90).aspx動作しますが、DelegateCommand を使用するとPrism ライブラリ CanExecuteChanged がユーザー コントロールで起動せず、その理由がわかりません。申し訳ありませんが、これは多くのコードです。Execute は正しく起動しますが、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;
    }
}
4

1 に答える 1

1

ここでの問題は、LinkClicked.RaiseCanExecuteChanged(); を呼び出していることです。DataContext を設定した直後とそれまでは LinkedCommand がバインドされていないため、DelegateCommand の CanExecuteChanged イベントは null であり、RaiseCanExecuteChanged() は何もしません。それまでバインディングが更新されるため、この呼び出しを回避するには、Window のロードされたイベントで LinkClicked.RaiseCanExecuteChanged() を呼び出します。これは汚い解決策ですが、この LinkBut​​ton を使用して Command をバインドするすべての場所でこれを行う必要があるためです。

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 を呼び出していないことです。実際の Command 実装では、CanExecute が呼び出されます。

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

これを行う場合、RaiseCanExecuteChanged を呼び出す必要はありません。

于 2014-08-15T17:11:13.473 に答える