WPF拖放不会触发Command Binding.CanExecute

时间:2009-05-22 02:10:23

标签: wpf drag-and-drop

是的,我知道这听起来很奇怪,但事实并非如此,问题是为什么,如果有解决方法的话。它适用于所有内容,即使您点击PrintScreen或Pause键,CanExecute也会触发。因此,在进行拖拽后,为了使其发射,您必须执行“其他”操作,例如鼠标单击,焦点,按键,任何内容。这将使事件触发,并允许Execute发生。无论如何,这是我的代码,我知道它很长,但它会帮助你帮助我。

我在我们的大型主项目中发现了这个错误,因此我将其简化为这个小应用程序以隔离问题。

XAML:

<Window x:Class="DragNDropCommands.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="485" SizeToContent="Width" Loaded="Window_Loaded">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.New" CanExecute="NewCanExecute" Executed="NewExecuted" />
        <CommandBinding Command="ApplicationCommands.Save" CanExecute="SaveCanExecute" Executed="SaveExecuted" />
        <CommandBinding Command="ApplicationCommands.Undo" CanExecute="UndoCanExecute" Executed="UndoExecuted" />
        <CommandBinding Command="ApplicationCommands.Redo" CanExecute="RedoCanExecute" Executed="RedoExecuted" />
    </Window.CommandBindings>
    <Grid Margin="8">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <Button Command="ApplicationCommands.New" Grid.Row="0" Grid.Column="0" FontWeight="Bold" Content="New" Width="80" Margin="8"></Button>
        <Button Command="ApplicationCommands.Save" Grid.Row="0" Grid.Column="1" FontWeight="Bold" Content="Save" Width="80" Margin="8"></Button>
        <Button Command="ApplicationCommands.Undo" Grid.Row="0" Grid.Column="2" FontWeight="Bold" Content="Undo" Width="80" Margin="8"></Button>
        <Button Command="ApplicationCommands.Redo" Grid.Row="0" Grid.Column="3" FontWeight="Bold" Content="Redo" Width="80" Margin="8"></Button>

        <CheckBox Grid.Row="1" Grid.Column="0" Margin="8" IsChecked="{Binding Path=AllowNew, Mode=TwoWay}">Allow New</CheckBox>
        <CheckBox Grid.Row="1" Grid.Column="1" Margin="8" IsChecked="{Binding Path=AllowSave}">Allow Save</CheckBox>
        <CheckBox Grid.Row="1" Grid.Column="2" Margin="8" IsChecked="{Binding Path=AllowUndo}">Allow Undo</CheckBox>
        <CheckBox Grid.Row="1" Grid.Column="3" Margin="8" IsChecked="{Binding Path=AllowRedo}">Allow Redo</CheckBox>

        <Label x:Name="labelDrag" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" BorderBrush="Black" BorderThickness="1" MouseDown="Label_MouseDown"
               Background="LightBlue" HorizontalContentAlignment="Center" Margin="8">Drag this label...</Label>
        <Label x:Name="labelDropNew" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" BorderBrush="Black" BorderThickness="1" Drop="labelDropNew_Drop"
               Background="LightGray" HorizontalContentAlignment="Center" Margin="8" AllowDrop="True">...here to toggle AllowNew</Label>
        <Label x:Name="labelDropSave" Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="2" BorderBrush="Black" BorderThickness="1" Drop="labelDropSave_Drop"
               Background="LightGray" HorizontalContentAlignment="Center" Margin="8" AllowDrop="True">...here to toggle AllowSave</Label>

        <ListBox x:Name="listViewLog" Grid.Row="4" Grid.ColumnSpan="4" Margin="8" Width="500">
        </ListBox>

        <Button Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" Margin="8" Click="Button_Click">Clear list</Button>
    </Grid>
</Window>

C#:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace DragNDropCommands
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private CommandControl commandControl = new CommandControl();
        private int canExecuteCount = 1;

        public Window1()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.DataContext = commandControl;
        }

        private void NewCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.commandControl == null || listViewLog == null)
                return;

            e.CanExecute = this.commandControl.AllowNew;

            listViewLog.Items.Add
            (
                String.Format
                (
                    "{0} - NewCanExecute: {1} - commandControl.AllowNew: {2}",
                    canExecuteCount++, e.CanExecute, commandControl.AllowNew
                )
            );
        }

        private void NewExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("New executed");
        }

        private void SaveCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.commandControl == null || listViewLog == null)
                return;

            e.CanExecute = this.commandControl.AllowSave;

            listViewLog.Items.Add
            (
                String.Format
                (
                    "{0} - SaveCanExecute: {1} - commandControl.AllowSave: {2}",
                    canExecuteCount++, e.CanExecute, commandControl.AllowSave
                )
            );
        }

        private void SaveExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("Save executed");
        }

        private void UndoCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.commandControl == null || listViewLog == null)
                return;

            e.CanExecute = this.commandControl.AllowUndo;

            listViewLog.Items.Add
            (
                String.Format
                (
                    "{0} - UndoCanExecute: {1} - commandControl.AllowUndo: {2}",
                    canExecuteCount++, e.CanExecute, commandControl.AllowUndo
                )
            );
        }

        private void UndoExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("Undo executed");
        }

        private void RedoCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.commandControl == null || listViewLog == null)
                return;

            e.CanExecute = this.commandControl.AllowRedo;

            listViewLog.Items.Add
            (
                String.Format
                (
                    "{0} - RedoCanExecute: {1} - commandControl.AllowRedo: {2}",
                    canExecuteCount++, e.CanExecute, commandControl.AllowRedo
                )
            );
        }

        private void RedoExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("Redo executed");
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            listViewLog.Items.Clear();
        }

        private void Label_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Label label = (Label)sender;

            if(e.LeftButton == MouseButtonState.Pressed)
                DragDrop.DoDragDrop(label, label, DragDropEffects.Move);
        }

        private void labelDropNew_Drop(object sender, DragEventArgs e)
        {
            this.commandControl.AllowNew = !this.commandControl.AllowNew;
        }

        private void labelDropSave_Drop(object sender, DragEventArgs e)
        {
            this.commandControl.AllowSave = !this.commandControl.AllowSave;
        }
    }

    public class CommandControl : DependencyObject
    {
        public bool AllowNew
        {
            get { return (bool)GetValue(AllowNewProperty); }
            set { SetValue(AllowNewProperty, value); }
        }

        // Using a DependencyProperty as the backing store for AllowNew.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AllowNewProperty =
            DependencyProperty.Register("AllowNew", typeof(bool), typeof(CommandControl), new UIPropertyMetadata(false));

        public bool AllowSave
        {
            get { return (bool)GetValue(AllowSaveProperty); }
            set { SetValue(AllowSaveProperty, value); }
        }

        // Using a DependencyProperty as the backing store for AllowSave.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AllowSaveProperty =
            DependencyProperty.Register("AllowSave", typeof(bool), typeof(CommandControl), new UIPropertyMetadata(false));

        public bool AllowUndo
        {
            get { return (bool)GetValue(AllowUndoProperty); }
            set { SetValue(AllowUndoProperty, value); }
        }

        // Using a DependencyProperty as the backing store for AllowUndo.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AllowUndoProperty =
            DependencyProperty.Register("AllowUndo", typeof(bool), typeof(CommandControl), new UIPropertyMetadata(false));

        public bool AllowRedo
        {
            get { return (bool)GetValue(AllowRedoProperty); }
            set { SetValue(AllowRedoProperty, value); }
        }

        // Using a DependencyProperty as the backing store for AllowRedo.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AllowRedoProperty =
            DependencyProperty.Register("AllowRedo", typeof(bool), typeof(CommandControl), new UIPropertyMetadata(false));
    }
}

您应该能够只复制粘贴并执行一些名称更改(文件,命名空间)以使其运行。我真的很喜欢你的帮助,因为这让我疯了,现在我终于发现了这个错误的原因,我不知道该怎么办。

任何建议都是真实的。

提前致谢。

1 个答案:

答案 0 :(得分:6)

快速建议:

您可以在拖放事件处理程序中使用CommandManager.InvalidateRequerySuggested()来强制重新执行CanExecute()。 (Link