2013-07-17 43 views
1

我很难过,在教程和关于此主题的帖子中围绕着逻辑。我试图在我正在写的wpf应用程序中实现它。mvvm与canexecute和绑定命令混淆

基本上,我使用一个列表框来显示列表中的对象的ToString,并允许用户通过添加和删除按钮添加和删除列表及其相应的列表框。我遇到的问题是执行“删除”按钮。如果没有选择列表框项目,我希望按钮被禁用,这是该模式适合的事情之一。我失去了如何实现这一条件。

此刻,当我突出显示一个列表框项目时,该按钮未启用。我想CanExecuteChanged事件不会触发。我该如何改变它?

我CommandsHandler类:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Input; 

namespace TechopsTools 
{ 

    public class CommandHandler : ICommand 
    { 
     private Action<object> _execute; 
     private bool _canExecute; 

     public CommandHandler(Action<object> execute) 
      : this(execute, true) 
     { 
     } 

     public CommandHandler(Action<object> execute, bool canExecute) 
     { 
      if (execute == null) 
       throw new ArgumentNullException("execute"); 

      _execute = execute; 
      _canExecute = canExecute; 
     } 


     public bool CanExecute(object parameter) 
     { 
      return _canExecute; 
     } 

     public void Execute(object parameter) 
     { 
      _execute(parameter); 
     } 

     public event EventHandler CanExecuteChanged 
     { 
      add { CommandManager.RequerySuggested += value; } 
      remove { CommandManager.RequerySuggested -= value; } 
     } 
    } 

} 

我的视图模型:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net; 
using System.Text; 
using System.Threading.Tasks; 
using ProtoBuf; 
using System.Windows; 
using System.ComponentModel; 
using System.Collections.ObjectModel; 
using System.Windows.Input; 

namespace TechopsTools 
{ 
    class LogCheckClientViewModel : INotifyPropertyChanged 
    { 
     private string uri; 
     private string response; 
     private bool _canRemove; 
     private LogConstraints selectedConstraints; 

     private ObservableCollection<LogConstraints> constraints; 

     public event PropertyChangedEventHandler PropertyChanged; 

     public LogConstraints SelectedConstraints 
     { 
      get 
      { 
       return selectedConstraints; 
      } 
      set 
      { 
       selectedConstraints = value; 
       OnPropertyChanged("SelectedConstraints"); 
      } 
     } 

     private CommandHandler removeItemCommand; 
     public ICommand RemoveItemCommand 
     { 
      get 
      { 
       if (removeItemCommand == null) 
        removeItemCommand = new CommandHandler(param => RemoveConstraint(), SelectedConstraints != null); 
       return removeItemCommand; 
      } 
     } 

     public string Response 
     { 
      get 
      { 
       return response; 
      } 
      set 
      { 
       response = value; 
       OnPropertyChanged("Response"); 
      } 
     } 

     public string Uri 
     { 
      get 
      { 
       return uri; 
      } 
      set 
      { 
       uri = value; 
       OnPropertyChanged("Uri"); 
      } 
     } 

     public ObservableCollection<LogConstraints> Constraints 
     { 
      get 
      { 
       return constraints; 
      } 
      set 
      { 
       constraints = value; 
       OnPropertyChanged("Constraints"); 
      } 
     } 

     public LogCheckClientViewModel() 
     { 
      constraints = new ObservableCollection<LogConstraints>(); 
     } 

     public void AddConstraint() 
     { 
      NewConstraint newConstraint = new NewConstraint(); 
      newConstraint.ShowDialog(); 
      if (newConstraint._vm.constraint != null) 
      { 
       constraints.Add(newConstraint._vm.constraint); 
      } 
     } 

     private void RemoveConstraint() 
     { 
      Constraints.Remove(SelectedConstraints); 
      OnPropertyChanged("Constraints"); 
     } 

XAML:

<Window x:Class="TechopsTools.LogCheckClient" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:TechopsTools" 
     Title="LogCheck" Height="453.057" Width="495.986"> 
    <Grid> 
     <TextBox Text="{Binding Response}" HorizontalAlignment="Left" Height="128" Margin="38,212,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="413" VerticalScrollBarVisibility="Auto" IsEnabled="False"/> 
     <Label Content="Response" HorizontalAlignment="Left" Margin="38,188,0,0" VerticalAlignment="Top" Width="78" Height="24"/> 
     <TextBox Text="{Binding Uri}" HorizontalAlignment="Left" Height="23" Margin="38,26,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="413"/> 
     <Label Content="Uri" HorizontalAlignment="Left" Margin="38,0,0,0" VerticalAlignment="Top" Width="78" Height="24"/> 
     <Button Content="Add Constraint" HorizontalAlignment="Left" Margin="38,54,0,0" VerticalAlignment="Top" Width="127" Height="56" Click="Add_Click"/> 
     <Button x:Name="Submit" Content="Submit Request" HorizontalAlignment="Left" Margin="38,345,0,0" VerticalAlignment="Top" Width="413" Height="70" Click="Submit_Click"/> 
     <ListBox SelectedItem="{Binding Path=SelectedConstraints,UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding Constraints}" HorizontalAlignment="Left" Height="124" Margin="182,54,0,0" VerticalAlignment="Top" Width="269"> 
      <ListBox.ItemTemplate> 
       <DataTemplate> 
        <StackPanel Orientation="Horizontal"> 
         <TextBlock Text="{Binding Path=description}" /> 
        </StackPanel> 
       </DataTemplate> 
      </ListBox.ItemTemplate> 
     </ListBox> 
     <Button Command="{Binding RemoveItemCommand}" Content="Remove Constraint" HorizontalAlignment="Left" Margin="38,122,0,0" VerticalAlignment="Top" Width="127" Height="56" /> 
    </Grid> 
</Window> 
+0

你最好试图找到一个框架,为MVVM提供支持类。我个人最喜欢的是棱镜。 –

回答

4

你确实需要使用CanExecute委托你做同样的方式一个Execute处理程序。

基本上现在您正在检查是否可以在RemoveItemCommand第一次访问时执行。但是,它只是在整个时间保持这个价值。

如果你通过一个具有相同条件的代理(可能是添加一个空列表,而不仅仅是一个空列表),我敢打赌它会工作。

换句话说,在你CommandHandler,改变

private bool _canExecute; 

private Func<bool,object> _canExecute; 

,改变

public bool CanExecute(object parameter) 
{ 
    return _canExecute; 
} 

public bool CanExecute(object parameter) 
{ 
    return _canExecute(parameter); 
} 

,然后在您的视图模型,改变

removeItemCommand = new CommandHandler(param => RemoveConstraint(), 
             SelectedConstraints != null); 

removeItemcommand = new CommandHandler(param => RemoveConstraint(), 
             param => SelectedConstraints != null); 

(注意,这可能不是正好正确的代码,因为我只写它的写意,但希望你点)

+0

我真的不知道委托人的工作方式以及CanExecute()中的更改是否给出了错误“Delegate Func 具有一些无效参数”此外,您能否解释为什么在此使用委托可解决我的问题? – rcj

+0

好吧,使用'Predicate '做了它,一切正常。 – rcj

+1

基本上发生了什么事是你正在设置一个函数来告诉CommandHandler如何检查它是否可以执行。最初,你只是传递真或假一次,而价值卡住了。现在,每次'CanExecute()'被调用时,它都会调用您传入的函数并重新执行实际检查,找到新的“新鲜”真或假值。 – Tim

0

我认为这件事可以在您的XAML文件内完成,只需使用DataTrigger即可。

如果这个解决方案能满足你,请让我知道写评论,我会为你提供一些代码。

最好的问候