2009-05-22 44 views
3

是的,我知道这听起来很奇怪,但事实并非如此,问题在于为什么以及是否有解决办法。它可以处理所有事情,即使您点击PrintScreen或Pause键,CanExecute触发。所以在做一次拖拽之后,为了使它燃烧起来,你必须做其他的事情,比如点击鼠标,聚焦,击键,任何事情。这会使事件发生,并允许执行发生。无论如何,这是我的代码,我知道它很长,但它会帮助你。WPF Drag n drop不会触发CommanBinding.CanExecute

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

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)); 
    } 
} 

你应该能够只是复制粘贴,并做了一些名称的变化(文件,命名空间)得到它运行。我真的很喜欢你的帮助,因为这已经让我疯狂了,现在我终于发现了错误的原因,我不知道该怎么做。

任何建议是真正apreciatted。

在此先感谢。

回答

5

只是一个快速的建议:

你可以使用拖拽CommandManager.InvalidateRequerySuggested()拖放事件处理程序来强制CanExecute()再执行。 (Link

+0

哇什么是优雅的解决方案。非常感谢! – Carlo 2009-05-22 14:14:26