【问题标题】:Are "volatile" data bindings in Windows Forms possible?Windows 窗体中的“易失性”数据绑定是否可能?
【发布时间】:2011-03-23 19:53:01
【问题描述】:

假设我正在实现一个 Winforms UI,其中所有命令都遵循以下模式:

interface ICommand
{
    bool CanExecute { get; }
    void Execute();
}

触发此类命令的按钮或菜单项应具有以下设置:

  • 属性Enabled 绑定到命令的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(好像它是一个易失性字段),但 AFAIK 这不是 Winforms 数据绑定的工作方式。有人有解决这个问题的办法吗?


注意:我知道 WPF,顺便说一句。我的问题的背景是,我将在 WPF 的大方向上逐步改进现有的 Winforms 应用程序。但实际上使用 WPF 并因此摆脱我所询问的问题目前是不可行的。

【问题讨论】:

    标签: winforms data-binding inotifypropertychanged volatile command-pattern


    【解决方案1】:

    我对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

    希望对你有帮助

    【讨论】:

      【解决方案2】:

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

      例如,在您的虚构示例中,您可能有一个UserLoggedIn 事件。对此,您可以设置一个 5 分钟的计时器;当该计时器过去时,您会引发属性更改事件。

      如果您采用投票方式,那么您将面临两个危险:

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

      混合方法是 C++ 中的that taken by Microsoft Foundation Classes,它是在应用程序的消息循环空闲时进行此检查。当您知道只有用户界面交互会影响您的 CanExecute 属性时,这是一种合理的方法。

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • 我真的不愿意投票 - 几乎总有一些动作可以用来推动属性更改事件
        • 如果你想支持任意 CanExecute 属性,这些属性对改变状态的实体是透明的,你必须轮询。
        猜你喜欢
        • 2012-02-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-11
        • 1970-01-01
        相关资源
        最近更新 更多