是“不稳定的” Windows 窗体中的数据绑定可能吗?

发布于 2024-09-12 00:02:47 字数 1014 浏览 8 评论 0原文

假设我正在实现一个 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's CanExecute
  • event Click is linked to the command's Execute (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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

指尖上得阳光 2024-09-19 00:02:47

不管怎样,我都会实现 INotifyPropertyChanged(或者添加一个 CanExecuteChanged 事件,它具有相同的效果)。我会努力让对象知道何时在正确的时间引发属性更改事件,而不是轮询。

例如,在您的虚构示例中,您可能有一个 UserLoggedIn 事件。针对这种情况,你可以设置一个 5 分钟的计时器;当该计时器到期时,您将引发属性更改事件。

如果您采用轮询方法,那么您将面临两个危险:

  • 轮询太频繁,您的应用程序会消耗 CPU 检查尚未发生的事件(例如,每 10 秒轮询一次,看看 5 分钟是否到了)
  • 不轮询通常,绑定到 CanExecute 属性的控件会滞后于 UI 的其余部分(例如,进行文本选择和 CopyTextCommand.CanExecute 属性更新之间存在延迟

)方法是 C++ 中的Microsoft 基础类采用的方法,即只要应用程序的消息循环空闲,就进行此检查。当您知道只有用户界面交互可以影响您的 CanExecute 属性时,这是一种合理的方法。

I would implement INotifyPropertyChanged regardless (or add a CanExecuteChanged 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:

  • Polling too often, where your application consumes CPU checking for events that can't possibly happen yet (for instance, polling every 10 seconds to see if 5 minutes are up)
  • Not polling often enough, where controls bound to CanExecute properties lag the rest of the UI (for instance, a delay between making a text selection and the CopyTextCommand.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.

初与友歌 2024-09-19 00:02:47

使用Timer 不断轮询CanExecute 属性。当属性更改时引发 PropertyChanged 事件。

Use a Timer to constantly poll the CanExecute property. Raise the PropertyChanged event when the property changes.

输什么也不输骨气 2024-09-19 00:02:47

我对 Application.Idle 事件进行轮询,只要您可以执行的逻辑很简单,就不应该有任何问题。

这是我当前的“CommandManager”实现的摘录;

 public CommandManager()
    {
        Commands = new List<ICommand>();

        Binders = new List<ICommandBinder>
                      {
                          new ControlBinder(),
                          new MenuItemCommandBinder()
                      };

        Application.Idle += UpdateCommandState;
    }
 private void UpdateCommandState(object sender, EventArgs e)
    {
        Commands.Do(c => c.Enabled);
    }

(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;

 public CommandManager()
    {
        Commands = new List<ICommand>();

        Binders = new List<ICommandBinder>
                      {
                          new ControlBinder(),
                          new MenuItemCommandBinder()
                      };

        Application.Idle += UpdateCommandState;
    }
 private void UpdateCommandState(object sender, EventArgs e)
    {
        Commands.Do(c => c.Enabled);
    }

(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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文