我正在尝试根据ObservableCollection中的对象禁用菜单项。
MainViewModel:
public ObservableCollection<ThumbnailModel> Thumbnails { get; set; }
public MainWindowViewModel()
{
Thumbnails = new ObservableCollection<ThumbnailModel>();
this.CreateMenu();
}
private void CreateMenu()
{
//TODO: Add tooltip to menu with short description
var items = new List<MenuItemViewModel>();
var item = new MenuItemViewModel();
item.MenuText = "File";
item.MenuItems = new List<MenuItemViewModel> {
new MenuItemViewModel { MenuText = "Select all", MenuCommand = this.SelectAllCommand, IsEnabled = SelectAllCommand.CanExecute(Thumbnails) },
new MenuItemViewModel { MenuText = "Unselect all", MenuCommand = this.UnselectAllCommand, IsEnabled = true },
};
items.Add(item);
//And so on
MenuItems = items;
}
public ICommand SelectAllCommand
{
get
{
return this.selectAllCommand ??
(this.selectAllCommand = new DelegateCommand(SelectAll, ((t) => ((ObservableCollection<ThumbnailModel>)t).Any(o => !o.IsChecked))));
}
}
的Xaml:
<Window.Resources>
<!--Menu template-->
<HierarchicalDataTemplate DataType="{x:Type viewModels:MenuItemViewModel}"
ItemsSource="{Binding Path=MenuItems}">
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command"
Value="{Binding MenuCommand}"/>
<Setter Property="CommandParameter"
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
<Setter Property="IsEnabled"
Value="{Binding IsEnabled}"/>
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding MenuIcon}" />
<TextBlock Text="{Binding MenuText}" />
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
<Menu DockPanel.Dock="Top" ItemsSource="{Binding Path=MenuItems}" />
打开文件菜单时,我得到一个例外。
System.ArgumentNullException未处理HResult = -2147467261
Message = Value不能为null。参数名称:来源
来源= System.Core程序
PARAMNAME =源
堆栈跟踪: 在System.Linq.Enumerable.Any [TSource](IEnumerable1 source, Func
2谓词) at KoenHoefman.PhotoResizer.ViewModels.MainWindowViewModel.b__e(Object t)在d:\ 000 TFS中 工作区\ KoenHoefman.PhotoResizer \ MAIN \ KoenHoefman.PhotoResizer \的ViewModels \ MainWindowViewModel.cs:行 126 at KoenHoefman.PhotoResizer.ViewModels.DelegateCommand.CanExecute(Object 参数)在d:\ 000 TFS中 工作区\ KoenHoefman.PhotoResizer \ MAIN \ KoenHoefman.PhotoResizer \的ViewModels \ DelegateCommand.cs:行 95 在MS.Internal.Commands.CommandHelpers.CanExecuteCommandSource(ICommandSource) commandSource) 在System.Windows.Controls.MenuItem.UpdateCanExecute() 在System.Windows.Controls.MenuItem.HookCommand(ICommand命令) ...
起初我认为原因是MenuItems中没有项目。 但是,当我在菜单创建后运行以下代码时,它返回false(如预期的那样)。
var y = SelectAllCommand.CanExecute(Thumbnails);
知道这里出了什么问题,当然还有如何修复它?
更新
之前必须查看它,但是当命中CanExecute方法时,参数为null,尽管我已将其指定为Thumbnails
?
DelegateCommand:
using System;
using System.Windows.Input;
public class DelegateCommand : ICommand
{
private readonly Action<object> execute;
private readonly Predicate<object> canExecute;
public DelegateCommand(Action<object> execute)
: this(execute, null)
{}
public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
this.execute(parameter);
}
public bool CanExecute(object parameter) // parameter is null when breakpoint is hit
{
return this.canExecute == null || this.canExecute(parameter);
}
}
如果我正确理解谓词(不确定),则每次调用时都会执行该方法。但是我在分配时输入的参数怎么样?这只用过一次吗?
答案 0 :(得分:1)
谓词的定义是:
public delegate bool Predicate<in T>( T obj)
它所做的就是对obj进行某种类型的比较或测试,并返回true或false。我们一直在LINQ中看到这一点。
var myList = getEmployees();
var filter = myList.Where(p=>p.lastName == "Jones");
代表是&#34; p&#34;或参数,比较部分是谓词或bool值。请注意,传入的类型是&#34;暗示&#34;这是因为linq有一个静态类&#34;其中&#34;扩展方法允许最多传递任何集合类型,该类型将谓词作为参数。像这样:
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, int, bool> predicate
)
根据Delegate命令在MSFT站点上的示例,我们看到新创建的一个,第二个parm传递一个名为&#34; CanSubmit&#34;的方法(指针)。在需要时被召唤。
public MyClass()
{
this.submitCommand = new DelegateCommand<int?>(this.Submit, this.CanSubmit);
}
private bool CanSubmit(int? customerId)
{
return (customerId.HasValue && customers.Contains(customerId.Value));
}
答案 1 :(得分:0)
最后在完成代码的过程中弄明白了,一步一步地绊倒this question
原来那个
默认情况下,菜单项在其命令不可用时将被禁用 执行(CanExecute = false)。
(找不到MSDN中的任何引用?)
所以解决方案变得更加简单,因为我不再需要MenuItemViewModel
上的IsEnabled属性。
我的XAML现在看起来像:
<Window.Resources>
<!--Menu template-->
<HierarchicalDataTemplate DataType="{x:Type viewModels:MenuItemViewModel}"
ItemsSource="{Binding Path=MenuItems}">
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command"
Value="{Binding MenuCommand}"/>
<Setter Property="CommandParameter"
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
<!-- No longer needed. By default menu items become disabled when its command cannot be executed (CanExecute = false).
<Setter Property="IsEnabled"
Value="{Binding IsEnabled}"/>-->
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding MenuIcon}" />
<TextBlock Text="{Binding MenuText}" />
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
我的命令:
public ICommand SelectAllCommand
{
get
{
return this.selectAllCommand ?? (this.selectAllCommand = new DelegateCommand(SelectAll, delegate(object obj) { return Thumbnails.Any(t => !t.IsChecked); }));
}
}