我有一个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/

10-17 00:50