[KnowHow]WPF中Button状态不刷新的问题[Lianz]

 
1.         现象
当使用CanExecute控制Button是否Enable时,有时会出现Button状态没有刷新,除非对UI进行一些操作(例如改变Focus)。
 
2.         分析
这种情况经常发生在CanExecute的内部条件变了,但UI并没有响应
考虑如下代码
    publicclassSomeViewModel
    {
        privateboolcanDoSomething;
 
        publicICommandDoSomethingCommand { get; privateset; }
 
        privatevoidDoSomething()
        {
        }
 
        privateboolCanDoSomething()
        {
            returncanDoSomething;
        }
 
        publicSomeViewModel()
        {
            this.DoSomethingCommand=newRelayCommand(this.DoSomething, this.CanDoSomething);
        }
    }
canDoSomething变化后,并没人通知UI状态的变化,所以UI没有响应
 
3.         解决方法一
调用如下方法
CommandManager.InvalidateRequerySuggested();
调用时机应该为触发CanExecute变化之后
使用这种方式会引起以下一些问题
a)         此方法只能运行于UI线程
虽然MSDN没有明确说明,但从测试结果来看在后台线程调用上述方法是不起作用的,在调用前请确保代码运行在UI线程。
关于ST中常见的几种后台线程相关问题说明如下:
                         i.             IProgress对象的ProgressChanged事件
依赖于IProgress对象的实现。
Progress对象保证ProgressChanged事件运行在Progress对象创建的线程上
针对ST,一般来说Progress对象是在UI线程上创建的,也就是说其ProgressChanged事件运行在UI线程
SimpleProgress对象的ProgressChanged事件运行在调用Report方法的线程上
针对ST,一般来说Report方法由后台线程调用,也就是说其ProgressChanged事件运行在后台线程。
所以ViewModel层请确保使用Progress对象而不要使用SimpleProgress对象
                       ii.             Task对象的ContinueWith方法
运行在指定的TaskScheduler所指示的线程上,如果没有指定TaskScheduler,则运行在父Task所在的线程上
针对ST,一般来说DeviceService创建的Task对象都运行在后台线程。所以如果想运行在UI线程,请在UI线程获取TaskScheduler并传入ContinueWith方法
b)         此方法引起性能问题
此方法本质上会使所有Command重新检查其CanExecute,从而对性能造成影响
 
4.         解决方法二
调用对应CommandRaiseCanExecuteChanged方法
此方法未经测试,但可以想象到的问题如下
a)         此方法只能运行于UI线程
理由应该同上,猜测是WPF内部实现的问题
b)         此方法严重依赖于MVVMLight框架的RelayCommand对象
此方法并非ICommand接口提供的方法
 
5.         结论
推荐使用方法一解决,使用时注意线程问题。
如果性能问题严重考虑使用方法二或者探索其他解决办法

转载于:https://www.cnblogs.com/junbird-nest/archive/2013/03/14/2958707.html

WPF (Windows Presentation Foundation) ,可以通过绑定键盘快捷键到命令或事件处理器来实现按钮的快捷键功能。这通常通过使用`KeyBinding`或`InputBindings`来完成。以下是实现这一功能的步骤: 1. 在你的WPF应用的窗口或用户控件的XAML,找到或创建一个资源字典(`ResourceDictionary`)。 2. 在资源字典定义一个`KeyBinding`。这个绑定将指定一个键(Key)、一个修饰符(Modifiers,比如Ctrl, Alt等)和它应该触发的命令(Command)或事件处理器(Handler)。 3. 如果你使用的是命令,那么需要确保你的ViewModel或相应的数据上下文(DataContext)有一个实现了`ICommand`接口的命令对象,并在`KeyBinding`引用这个命令。 以下是一个简单的示例代码,展示了如何在XAML为一个按钮创建快捷键绑定: ```xml <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:input="http://schemas.microsoft.com/expression/2010/controls/KeyBinding" x:Class="YourNamespace.MainWindow" Title="MainWindow" Height="350" Width="525"> <Window.InputBindings> <!-- 定义一个快捷键绑定,这里以 Ctrl+S 为例 --> <input:KeyBinding Key="S" Modifiers="Control" Command="{Binding SaveCommand}" /> </Window.InputBindings> <!-- 确保你的ViewModel有SaveCommand的定义 --> <Grid> <!-- UI elements --> </Grid> </Window> ``` 在上面的例子,当用户按下 Ctrl+S 快捷键时,如果`SaveCommand`命令存在于ViewModel,并且处于可执行状态,那么将触发该命令。 请注意,如果是在后台代码处理快捷键,则可能需要使用`InputBindings`的事件处理器来实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值