今天有位网友对我说,他在WPF中使用Command时遇到了一个问题,场景如下,为一个Button实例设置了Command,并且添加了CommandBinding,然后后台开一个Timer线程不停地改变该Command的CanCommand属性,但是在界面上却并没有立即反应出来。
下面给出该重现该问题及其解决方案的代码
代码如下:
XAML Code
<Window x:Class="wpfCommand.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300" Loaded="Window_Loaded">
<Grid>
<Button Height="23" HorizontalAlignment="Left" Margin="40,0,0,41" Name="btnCanExecute" VerticalAlignment="Bottom" Width="Auto">Can Execute</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,45,41" Name="btnPaste" VerticalAlignment="Bottom" Width="75">_Paste</Button>
<TextBox Margin="17,21,25,92" Name="txtContent" />
</Grid>
</Window>
private bool canExecute = false;
private Timer timer = new Timer(2000);
public Window1()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
btnPaste.Command = ApplicationCommands.Paste;
btnPaste.CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste,new ExecutedRoutedEventHandler(executedRoutedEventHandler),new CanExecuteRoutedEventHandler(canExecuteRoutedEventHandler)));
timer.Elapsed +=new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
canExecute = !canExecute;
}
private void executedRoutedEventHandler(object sender, ExecutedRoutedEventArgs e)
{
txtContent.Text += Clipboard.GetText();
}
private void canExecuteRoutedEventHandler(object sender, CanExecuteRoutedEventArgs e)
{
//e.CanExecute = Clipboard.ContainsText();
e.CanExecute = canExecute;
}
解决方案
public partial class Window1 : Window
{
private bool canExecute = false;
private event EventHandler CanExecuteChanged;
private delegate void DoWork();
private Timer timer = new Timer(2000);
public Window1()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
CanExecuteChanged += new EventHandler(Window1_CanExecuteChanged);
btnPaste.Command = ApplicationCommands.Paste;
btnPaste.CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste,new ExecutedRoutedEventHandler(executedRoutedEventHandler),new CanExecuteRoutedEventHandler(canExecuteRoutedEventHandler)));
timer.Elapsed +=new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
void Window1_CanExecuteChanged(object sender, EventArgs e)
{
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, (DoWork)delegate()
{
DependencyObject focusScope = FocusManager.GetFocusScope(this);
UIElement focusElement = FocusManager.GetFocusedElement(focusScope) as UIElement;
if (!btnCanExecute.Equals(focusElement))
{
FocusManager.SetFocusedElement(focusScope, btnCanExecute);
}
else
{
focusElement = this;
}
if (focusElement == null)
{
FocusManager.SetFocusedElement(focusScope, this);
}
else
{
FocusManager.SetFocusedElement(focusScope, focusElement);
}
});
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
canExecute = !canExecute;
RaiseEvent();
}
private void executedRoutedEventHandler(object sender, ExecutedRoutedEventArgs e)
{
txtContent.Text += Clipboard.GetText();
}
private void canExecuteRoutedEventHandler(object sender, CanExecuteRoutedEventArgs e)
{
//e.CanExecute = Clipboard.ContainsText();
e.CanExecute = canExecute;
}
private void RaiseEvent()
{
EventHandler temp = CanExecuteChanged;
if (temp != null)
{
temp(this, new EventArgs());
}
}
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
base.OnClosing(e);
timer.Dispose();
}
}