代码之家  ›  专栏  ›  技术社区  ›  Manuel R.

Silverlight-将按钮上的IsEnabled属性绑定到ViewModel上的属性

  •  3
  • Manuel R.  · 技术社区  · 16 年前

    我正在构建一个Silverlight应用程序,我想在后台进行长时间运行操作时禁用一个按钮。 我使用的是MVVM,所以在ViewModel中我有一个名为SearchinProgress的属性。 现在,我想禁用搜索按钮,只要搜索过程为真。 在wpf中,我只需编写一个datatrigger,它将search按钮上的isEnabled设置为false。

    很遗憾,在Silverlight中没有DataTriggers,所以我正在寻找另一个解决方案。我试过和VisualStateManager开玩笑,但我什么都没弄到。对于我正在尝试实现的这个简单的事情,VSM似乎是多余的。

    感谢您的帮助。

    8 回复  |  直到 15 年前
        1
  •  7
  •   Richard Szalay    16 年前

    而不是跳过去 SearchInProgress=true 设置 IsEnabled=false ,为什么不创建一个 CanSearch 属性并绑定到该属性。属性可以是只读的(或具有私有的setter),另一个属性可以激发 PropertyChanged 代表活动。

    最后,视图模型的观点是您从视图中移除逻辑。将视图绑定到 SearchInProgress (因此,使用转换器来否定 IsEnabled )意味着视图理解 什么时候 它应该或不应该能够搜索。绑定到 搜查 但是,属性意味着当启用搜索时,视图模型可以完全控制,并且视图可以保持哑。

    或者,您可以使用与Blend一起安装的混合行为API,因为它们具有类似于数据触发器的功能。

        2
  •  1
  •   PL.    16 年前

    可以说,更好的方法是使用prism2中的delegatecommand,方法是将其附加到搜索按钮上,并在视图模型中实现其canexecute方法,以便返回!正在搜索。

    然后,当ViewModel启动搜索操作时,它会将searchinprogress更改为true(以便canexecute返回false),然后在搜索操作结束后,对命令调用raisecanecuetechanged(这将导致按钮被禁用),ViewModel会将searchinprogress更改回false(以便canexecute返回tru)e)然后再次调用raisecanecuetechanged(这将导致按钮被启用)

        3
  •  0
  •   Muad'Dib    16 年前

    为数据模型使用DependencyProperty或InotifyPropertiesChanged接口,然后绑定到公共属性SerachInProgress。我想你可能也要做一个转换器,来转换成布尔值的另一个。

        4
  •  0
  •   pete the pagan-gerbil    16 年前

    绑定到searchinprogress属性,但通过转换器运行它以反转布尔值。

    在装订过程中,

    IsEnabled="{Binding Path=SearchInProgress,Converter={StaticResource YOURCONVERTERHERE}}"
    

    在converter convert函数中,我认为应该是

    return !(value as bool)
    

    用任何健全的检查,你想把周围的空项目,等等。

        5
  •  0
  •   Manuel R.    16 年前

    目前我能想到的唯一合理的解决方案是在视图订阅的视图模型中完成一个事件“searchCompleted”,然后在事件触发时相应地更改视图。

        6
  •  0
  •   Alun Harford    16 年前

    完全没有理由为此将prism dll添加到您的项目中。您只需要10行代码和2个单元测试。

    不过,您仍然希望使用命令模式。添加一个带有“icommand”的“command”附加属性,设置该属性后,您可以:

    1. 观察命令并按要求启用或禁用按钮。
    2. 向按钮的“click”事件添加一个处理程序,该事件对命令调用“execute”方法。

    关于棱镜的一个注释:图书馆糟透了!但是 Composite Application Guidance Book 对于编写MVVM应用程序的任何人来说都是一个基本的阅读,并提供有关命令模式的更多信息。

        7
  •  0
  •   Manuel R.    16 年前

    我找到了一个我很满意的解决方案。 首先,我在布局根网格“searchinprogress”和“normal”上定义了两个VSM状态。

            <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="Standard">
                <VisualState x:Name="SearchInProgress">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="SearchButton" Storyboard.TargetProperty="(Control.IsEnabled)">
                            <DiscreteObjectKeyFrame KeyTime="00:00:00">
                                <DiscreteObjectKeyFrame.Value>
                                    <system:Boolean>False</system:Boolean>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="SearchCancelButton" Storyboard.TargetProperty="(Control.IsEnabled)">
                            <DiscreteObjectKeyFrame KeyTime="00:00:00">
                                <DiscreteObjectKeyFrame.Value>
                                    <system:Boolean>True</system:Boolean>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Normal"/>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
    

    非常简单,我可能会调整它们,但它是有效的。

    要在使用数据状态行为的状态之间切换 here 它允许我绑定到DataContext(ViewModel)上的属性,并相应地在两个状态之间切换:

            <interactivity:Interaction.Behaviors>
            <exprsamples:DataStateBehavior Binding="{Binding Path=SearchIsInProgress, Mode=TwoWay}"
                                           Value="True"
                                           TrueState="SearchInProgress"
                                           FalseState="Normal">
            </exprsamples:DataStateBehavior>
        </interactivity:Interaction.Behaviors>
    

    我认为我现在能够使用VSM的强大功能、混合的可设计性和“datatrigger”机制的灵活性来充分发挥作用。

        8
  •  0
  •   Mike Post    15 年前

    您需要创建一个命令并将其绑定到按钮。你要找的所有东西都为你烤进了运行时。像mvvm light和prism这样的框架可以很容易地创建新的命令,但是您可以这样做:

    创建实现ICommand的类。给它一个名为searchinprogress的私有bool。搜索开始时,将SearchinProgress设置为true。搜索完成后(成功或因超时、中止等原因),将SearchinProgress设置为false。实现ICommand.CanExecute返回!正在搜索。在视图模型上公开搜索图标命令,然后将按钮的命令属性绑定到视图模型上的命令。

    伪代码:

    public class MySearchCommand : ICommand
    {
      public event EventHandler CanExecuteChanged;
      private bool _searching;
      private bool SearchInProgress
      {
        get { return _searching; }
        set
        {
          if (_searching == value) return;
          _searching = value;
          if (CanExecuteChanged != null) CanExecuteChanged(this, EventArgs.Empty);
        }
    
      public bool CanExecute(object param)
      {  return !SearchInProgress }
    
      public void Execute(object param)
      {
        try
        {
          SearchInProgress = true;
          // search code here including callback to OnSearchCompleted method
        }
        catch(Exception ex)
        {
          SearchInProgress = false;
        }
      }
    
      private void OnSearchCompleted(SomeCallbackResult result)
      {
        SearchInProgress = false;
      }
    }
    
    public class ViewModel : INotifyPropertyChange
    {
      public ICommand SearchCommand { get; private set; }
      public ViewModel()
      {
        SearchCommand = new MySearchCommand();
      }
    }
    

    XAML:

    <UserControl ....>
      <UserControl.DataContext>
        <ViewModel />
      </UserControl.DataContext>
      <Grid>
        <Button Command={Binding SearchCommand} />
      </Grid>
    </UserControl>