今天有位网友对我说,他在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>

C# Code
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;
}
的确,我试了下,只有在焦点切换时才会更新,当然,Command的内部原理我没有去了解过,相信通过了解内部机制会更好更容易的解决这个问题,我只是从表层出发,既然切换焦点可以使得Command更新,那么我们可以在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();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端