如何使用wpf和mvvm中的动态菜单获得正确的CommandParameter绑定

如何使用wpf和mvvm中的动态菜单获得正确的CommandParameter绑定,wpf,menu,mvvm-light,fody-propertychanged,wvvm,Wpf,Menu,Mvvm Light,Fody Propertychanged,Wvvm,我正在WPF应用程序中实现一个动态菜单服务。每个命令都可以或应该有不同的CommandParameters 问题: 使用我在xaml中设置CommandParameter绑定的解决方案,可以从命令DoeSentUpdate获得CanExecute属性 到目前为止我拥有的 我正在使用mvvm light和fody propertychanged 这里是菜单类: public class MyMenu : INotifyPropertyChanged { private Observable

我正在WPF应用程序中实现一个动态菜单服务。每个命令都可以或应该有不同的CommandParameters

问题: 使用我在xaml中设置CommandParameter绑定的解决方案,可以从命令DoeSentUpdate获得CanExecute属性

到目前为止我拥有的

我正在使用mvvm light和fody propertychanged

这里是菜单类:

public class MyMenu : INotifyPropertyChanged
{
    private ObservableCollection<MyMenu> myChildren;

    public MyMenu()
    {
        myChildren = new ObservableCollection<MyMenu>();
    }
    public string Header { get; set; }
    public string Image { get; set; }
    public string CommandName { get; set; } //used to set the CommandParameter binding
    public ICommand Command { get; set; }
    public ObservableCollection<MyMenu> Children {
        get
        {
            return myChildren;
        }
        private set
        {
            myChildren = value;
        }
    } 


    public event PropertyChangedEventHandler PropertyChanged;
}
然后,我在viewmodel中有一个可绑定属性:

public ObservableCollection<MyMenu> MainMenu
{
    get
    {
        return myMenuService.MainMenu;
    }
}
public observetecollection主菜单
{
得到
{
返回myMenuService.main菜单;
}
}
此处命令实现为RelayCommand:

//in the constructor
OpenSelectTestprocedureWindowCommand = new RelayCommand<ShowTestschrittViewParameter>(OpenSelectTestablaufWindow, CanOpenSelectTestablaufWindow);
OpenUserLoginDialogCommand = new RelayCommand<Type>(OpenUserLoginDialog);

private void OpenUserLoginDialog(Type aWindowType)
{
    myNavigationService.ShowWindowModal(aWindowType);
}

private bool CanOpenSelectTestablaufWindow(ShowTestschrittViewParameter showTestschrittViewParameter)
{
    if (myDataService.CurrentTestProcedure != null)
    {
        if (myDataService.CurrentTestProcedure.TestProcedureState == Logic.Model.GlobalTypes.TestProcedureState.Running) return false;
    }
    return new ViewModelLocator().UserLoginDialogViewModel.User.NameIsValid;
}

private void OpenSelectTestablaufWindow(ShowTestschrittViewParameter showTestschrittViewParameter)
{
    myNavigationService.ShowTestschrittView(showTestschrittViewParameter);
}
//在构造函数中
OpenSelectTestprocedureWindowCommand=newrelaycommand(OpenSelectTestablaufWindow,CanOpenSelectTestablaufWindow);
OpenUserLoginDialogCommand=新的RelayCommand(OpenUserLoginDialog);
私有void OpenUserLoginDialog(类型aWindowType)
{
myNavigationService.ShowWindowModal(aWindowType);
}
专用bool CANopenSelectTestBlaufWindow(ShowTestschrittViewParameter ShowTestschrittViewParameter)
{
if(myDataService.CurrentTestProcedure!=null)
{
if(myDataService.CurrentTestProcedure.TestProcedureRate==Logic.Model.GlobalTypes.TestProcedureRate.Running)返回false;
}
返回新的ViewModelLocator().UserLoginDialogViewModel.User.NameIsValid;
}
私有void openselectTestBlaufWindow(ShowTestschrittViewParameter ShowTestschrittViewParameter)
{
myNavigationService.ShowTestschrittView(ShowTestschrittView参数);
}
然后在MainView中,我有以下xaml:

<Menu Grid.Row="2" ItemsSource="{Binding MainMenu}" Name="DynamicMenu">
    <!--<Menu.ItemTemplate>
        <DataTemplate DataType="{x:Type luih:MyMenu}">
            <StackPanel>
                    <Label Content="{Binding Header}"/>
                    <Image Source="{Binding Image}"/>
                </StackPanel>
        </DataTemplate>
    </Menu.ItemTemplate>-->
    <Menu.ItemContainerStyle>
        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="Header" Value="{Binding Header}"/>
            <Setter Property="Command" Value="{Binding Command}"/>
            <Setter Property="ItemsSource" Value="{Binding Children}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding CommandName}" Value="OpenUserLoginDialogCommand">
                    <Setter Property="CommandParameter" Value="{x:Type local:UserLoginDialog}"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding CommandName}" Value="OpenSelectTestprocedureWindowCommand">
                    <Setter Property="CommandParameter" Value="{x:Type local:UserLoginDialog}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Menu.ItemContainerStyle>
</Menu>

注意。xaml中的CommandParameter绑定类型当前不正确。这是另一个问题,我会自己解决。但出于测试目的,它应该可以工作。它将给我一个例外,因为错误的类型

但是,当我用Style.Trigger和DataTrigger绑定CommandParameter时,CanExecute属性在运行时不再发送更新。当我评论这一部分时,一切都很好。但是我没有命令参数


欢迎提供任何帮助和建议。

我发现了这个问题

mvvm light的RelayCommand评估CanExecute函数的参数类型。这必须是正确的声明类型或null

因此,出于测试目的,我必须如下设置绑定:

 <Style TargetType="{x:Type MenuItem}">
    <Setter Property="CommandParameter" Value="{x:Null}"/>
</Style>

<Menu Grid.Row="2" ItemsSource="{Binding MainMenu}" Name="DynamicMenu">
    <!--<Menu.ItemTemplate>
        <DataTemplate DataType="{x:Type luih:MyMenu}">
            <StackPanel>
                    <Label Content="{Binding Header}"/>
                    <Image Source="{Binding Image}"/>
                </StackPanel>
        </DataTemplate>
    </Menu.ItemTemplate>-->
    <Menu.ItemContainerStyle>
        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="Header" Value="{Binding Header}"/>
            <Setter Property="Command" Value="{Binding Command}"/>
            <Setter Property="ItemsSource" Value="{Binding Children}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding CommandName}" Value="OpenUserLoginDialogCommand">
                    <Setter Property="CommandParameter" Value="{x:Type local:UserLoginDialog}"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding CommandName}" Value="OpenSelectTestprocedureWindowCommand">
                    <Setter Property="CommandParameter" Value="{x:Type local:UserLoginDialog}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Menu.ItemContainerStyle>
</Menu>
 <Style TargetType="{x:Type MenuItem}">
    <Setter Property="CommandParameter" Value="{x:Null}"/>
</Style>