是“不稳定的” Windows 窗体中的数据绑定可能吗?
假设我正在实现一个 Winforms UI,其中所有命令都遵循以下模式:
interface ICommand
{
bool CanExecute { get; }
void Execute();
}
触发此类命令的按钮或菜单项应具有以下设置:
- 属性
Enabled
绑定到命令的 < code>CanExecute - 事件
Click
链接到命令的Execute
(由于方法签名不同,通过中间事件处理程序
) >CanExecute 是,实现 INotifyPropertyChanged
因为它在这里不起作用,因为这个属性不能直接修改,而是取决于程序中的其他因素,而无需修改与命令有关。并且不必在程序中完全不相关的部分中触发命令的 PropertyChanged
事件。
当 CanExecute
发生更改时,如何让数据绑定管理器知道?
这是我的问题的一个(纯粹虚构的)示例:
bool CanExecute
{
get
{
return User.LoggedInForAtLeastNMinutes(5);
// how would you trigger data-binding updates for CanExecute?
}
}
理想情况下,我希望 UI 不断检查 CanExecute
(就好像它是一个易失性字段),但据我所知,这不是 Winforms 数据绑定的方式作品。有人有解决这个问题的办法吗?
注意:顺便说一句,我知道 WPF。我的问题的背景是我将在WPF的大方向上逐步改进现有的Winforms应用程序。但实际上使用 WPF 来解决我所询问的问题目前是不可行的。
Let's assume I'm implementing a Winforms UI where all commands adhere to the following pattern:
interface ICommand
{
bool CanExecute { get; }
void Execute();
}
Buttons or menu items that trigger such a command should have the following set-up:
- property
Enabled
is bound to the command'sCanExecute
- event
Click
is linked to the command'sExecute
(through an intermediate event handler due to the differing method signatures)
The trouble with CanExecute
is, implementing INotifyPropertyChanged
for it won't work here, as this property cannot be directly modified, but depends on other factors in the program which needn't be related to the command. And one shouldn't have to trigger the command's PropertyChanged
event in completely unrelated parts of the program.
How do you let the data binding manager know when CanExecute
has changed?
Here's a (purly fictional) example of my problem:
bool CanExecute
{
get
{
return User.LoggedInForAtLeastNMinutes(5);
// how would you trigger data-binding updates for CanExecute?
}
}
Ideally, I'd like to have the UI constantly checking CanExecute
(as if it were a volatile field), but AFAIK this is not how Winforms data binding works. Does anyone have a solution for this problem?
Note: I am aware of WPF, btw. The background of my question is that I'm going to gradually improve an existing Winforms application in the general direction of WPF. But actually using WPF and thus getting rid of the problem I've asked about is not feasible right now.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不管怎样,我都会实现 INotifyPropertyChanged(或者添加一个 CanExecuteChanged 事件,它具有相同的效果)。我会努力让对象知道何时在正确的时间引发属性更改事件,而不是轮询。
例如,在您的虚构示例中,您可能有一个
UserLoggedIn
事件。针对这种情况,你可以设置一个 5 分钟的计时器;当该计时器到期时,您将引发属性更改事件。如果您采用轮询方法,那么您将面临两个危险:
)方法是 C++ 中的Microsoft 基础类采用的方法,即只要应用程序的消息循环空闲,就进行此检查。当您知道只有用户界面交互可以影响您的
CanExecute
属性时,这是一种合理的方法。I would implement
INotifyPropertyChanged
regardless (or add aCanExecuteChanged
event, which has the same effect). I would try hard for objects to know when to raise the property changed event at the right time, rather than polling.For instance, in your fictional example, you could have a
UserLoggedIn
event. In response to that, you could set a 5-minute timer; when that timer elapses, you raise the property changed event.If you go for the polling approach then you face two dangers:
CanExecute
properties lag the rest of the UI (for instance, a delay between making a text selection and theCopyTextCommand.CanExecute
property updating)A hybrid approach is that taken by Microsoft Foundation Classes in C++, which was to make this check any time the application's message loop was idle. This is a reasonable approach when you know that only user interface interaction that can affect your
CanExecute
property.使用
Timer
不断轮询CanExecute
属性。当属性更改时引发PropertyChanged
事件。Use a
Timer
to constantly poll theCanExecute
property. Raise thePropertyChanged
event when the property changes.我对 Application.Idle 事件进行轮询,只要您可以执行的逻辑很简单,就不应该有任何问题。
这是我当前的“CommandManager”实现的摘录;
(Do() 只是一个执行 foreach 的扩展方法,类似于 linq Select() 但采用 Action 而不是 Func)
我前段时间已经在博客中讨论过这一点,请随时查看: http://codewithpassion.blogspot.com/2010/11/icommand-and-commandmanager-for- windows.html
希望有帮助
I' do the polling on the Application.Idle event, as long as your can execute logic is simple, there shouldn't be any problem.
here is an extract of my current 'CommandManager' implementation;
(Do() is just an extension method that does a foreach, like linq Select() but taking Action instead of Func)
I've blogged about this some time ago, feel free to check: http://codewithpassion.blogspot.com/2010/11/icommand-and-commandmanager-for-windows.html
hope it helps