2010-02-22 131 views
3

我正在构建Silverlight应用程序,并且我想在后台正在进行长时间运行的操作时禁用按钮。 我使用MVVM,所以在ViewModel中我有一个名为SearchInProgress的属性。 现在我想每当SearchInProgress为true时禁用搜索按钮。 在WPF中,我只需编写一个DataTrigger,将搜索按钮上的IsEnabled设置为false。Silverlight - 将按钮上的IsEnabled属性绑定到ViewModel上的属性

很遗憾,DataTriggers在Silverlight中不可用,所以我正在寻找另一种解决方案。我尝试过使用VisualStateManager,但我没有得到任何地方。对于我试图实现的这个简单的事情来说,VSM看起来似乎有点矫枉过正。

任何帮助表示赞赏。

回答

0

我发现了一个我很满意的解决方案。 首先我在LayoutRoot网格的'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的(视图模型)一个属性,因此两种状态之间切换,我用的是DataStateBehavior状态之间切换:我觉得我现在能

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

使用VSM的强大功能,Blend中的可设计性以及“DataTrigger”机制的灵活性以达到全面效果。

0

对数据模型使用DependencyProperty或INotifyPropertyChanged接口,然后绑定到公共属性SerachInProgress。我想你可能也必须制作一个转换器,以转换为布尔值的相反。

0

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

在Binding,像

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

在转换器转换功能,我认为这将是

return !(value as bool) 

与任何理智检查你想要把周围的空项目等

+0

我认为这工作,但如果我想在同一时间在GUI中改变一些事情,这可能得到有点凌乱。 – 2010-02-23 08:52:17

1

可以说更好的方法是使用Prism2中的DelegateCommand,将其附加到搜索按钮并在ViewModel中实现CanExecute方法,以便返回s!SearchInProgress。

然后,当ViewModel启动搜索操作时,它会将SearchInProgress更改为true(以便CanExecute返回false),然后在命令上调用RaiseCanExecuteChanged(这将导致按钮被禁用)。一旦搜索操作结束ViewModel会将SearchInProgress更改为false(以便CanExecute返回true),然后再次调用RaiseCanExecuteChanged(这将导致按钮被启用)。

+1

我想避免使用此项目的框架。 – 2010-02-23 08:57:48

0

我现在唯一能想到的合理解决方案是有一个ViewModel中的视图所订阅的事件“SearchCompleted”,然后在事件触发时相应地更改视图。

7

与其跳过箍环SearchInProgress=true设置IsEnabled=false,为什么不创建CanSearch属性并绑定到该属性。该物业可以是只读的(或有一个私人二传手),并且其他物业可以代表它发射PropertyChanged事件。

最终,视图模型的重点是从视图中删除逻辑。将视图绑定到SearchInProgress(因此,使用转换器取消IsEnabled)意味着该视图理解它应该或不应该能够搜索。但是,绑定到CanSearch属性意味着视图模型在搜索已启用且视图可以保持愚蠢时具有完全控制权。

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

+0

好点。我会研究你提到的两件事。 – 2010-02-23 09:32:54

+0

尽管我想避免的是,绑定到CanSearch属性上的每个控件,我想要禁用或更改时进行搜索。如果可能,我宁愿将它放在一个地方。 – 2010-02-23 12:32:52

+0

我个人比较喜欢在每个位置使用XAML绑定,但是如果不这样做,您可以始终跟踪后面代码中的'PropertyChanged'事件并更新每个适用控件的IsEnabled属性。 (请记住,如果您使用OneWay绑定来更改属性的值,则会删除绑定) – 2010-02-23 15:01:56

0

绝对没有理由将PRISM dll添加到您的项目中。你只需要10行代码和2个单元测试。

虽然你仍然想使用命令模式。添加一个“命令”附加属性,该属性需要一个'ICommand',当属性设置为:

  1. 观察命令并启用或禁用按钮。
  2. 向按钮的“Click”事件添加一个处理程序,该事件在该命令上调用“Execute”方法。

关于PRISM的一个注意事项:库吸!但是对于任何编写MVVM应用程序的人来说,Composite Application Guidance Book都是必不可少的阅读,并提供了关于命令模式的更多信息。

0

您需要创建一个命令并将其绑定到按钮。所有你正在寻找的东西都会被运行到你的运行环境中。 MVVM Light和Prism等框架可以轻松创建新命令,但您可以自己这样做:

创建一个实现ICommand的类。给它一个名为SearchInProgress的私人布尔。搜索开始时,将SearchInProgress设置为true。当搜索完成(成功或由于超时,被中止等)将SearchInProgress设置为false。具有ICommand.CanExecute的实现返回!SearchInProgress。在您的视图模型上公开Search ICommand,然后将按钮的command属性绑定到视图模型上的命令。

伪代码:

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> 
相关问题