我有一个WPF应用程序。我正在使用MVVM模式。我有一本字典:
public abstract class ViewModelBase
{
public static Dictionary<string, Action> Permissions { get; set; }
...
}
我想将其值绑定(bind)到菜单项的可见性,如下所示:
<MenuItem x:Name="systemMenuItem" Header="System" Visibility="{Binding Permissions[systemMenuItem].CanBeShow, Converter={StaticResource BoolToVis}}">...</MenuItem>
要填充此字典,我需要窗口构建可视树,因为字典的元素包含来自窗口MenuItem的信息。如果我将在InitializeComponent之前创建字典,则会得到一个异常,即没有值
systemMenuItem
的键,因为VisualTreeHelper.GetChildrenCount
返回零个元素。如果我在Loaded
事件上执行此操作,我将获得正常的已填充字典,但在这种情况下绑定(bind)不起作用。如何在窗口显示给用户并从MenuItems获取信息之前填充字典?在那种情况下我该如何使装订工作呢?该窗口是主窗口和启动窗口。 最佳答案
作为使用字典进行绑定(bind)的一般规则是一个坏主意,这可能就是MS从未将.observable Dictionary作为.Net框架的一部分创建的原因,最好的选择是创建一个Permission类,然后拥有它们的Observable集合,这将为您提供集合绑定(bind)和Permission上的更改绑定(bind)
注意:这使用C#6,因此,如果您使用的是较早版本,则可能需要对其进行调整
例子
Xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<DockPanel>
<Menu DockPanel.Dock="Top" ItemsSource="{Binding Permissions}">
<Menu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Name}"/>
<Setter Property="Visibility" Value="{Binding CanBeShow, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<Setter Property="Command" Value="{Binding Action}"/>
</Style>
</Menu.ItemContainerStyle>
</Menu>
<Grid/>
</DockPanel>
</Window>
查看模型
public class ViewModel
{
public ViewModel()
{
//some dummy data
Permissions.Add(new Permission()
{
Name = "Open",
CanBeShow = true,
Action = ApplicationCommands.Open
});
Permissions.Add(new Permission()
{
Name = "Save",
CanBeShow = false,
Action = ApplicationCommands.Save
});
Permissions.Add(new Permission()
{
Name = "Delete",
CanBeShow = true,
Action = ApplicationCommands.Delete
});
}
public ObservableCollection<Permission> Permissions { get; } = new ObservableCollection<Permission>();
//notice no set you want to change the content of the collection not the collection
}
public class Permission:INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
}
}
private bool canBeShow;
public bool CanBeShow
{
get { return canBeShow; }
set
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CanBeShow)));
canBeShow = value;
}
}
private ICommand action;
public ICommand Action
{
get { return action; }
set {
action = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Action)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
但是,如果您尝试对菜单操作实现某种安全性,
那么执行此操作的首选方法将是重写ICommand以创建一个Custom Command,该Custom Command将查找其自身的权限并将其作为属性公开,而不会靠近View
public class PermissionCommand:INotifyPropertyChanged,ICommand
{
public event EventHandler CanExecuteChanged;
public event PropertyChangedEventHandler PropertyChanged;
private string name;
public string Name
{
get { return name; }
set
{
name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
}
}
public bool CanBeShow
{
get
{
//Check permissions for CanBeShow here
}
}
public bool CanExecute(object parameter)
{
//Check permissions for Execution here
}
public void Execute(object parameter)
{
// perform action here
}
//you will need to trigger the events when the permissions change
}
关于c# - 如果字典填充较晚,则绑定(bind)不适用于字典,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39351100/