Как получить правильную привязку CommandParameter с динамическими c меню в wpf и mvvm - PullRequest
0 голосов
/ 08 февраля 2020

Я использую сервис динамического меню c в моем приложении WPF. Каждая команда может или должна иметь разные CommandParameters.

Проблема: Благодаря моему решению установить привязку CommandParamter в xaml свойство CanExecute из команды doesent update больше.

Что у меня до сих пор

Я использую 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;
}

Это Класс используется MenuService:

public sealed class MenuService : INotifyPropertyChanged
{
    private static readonly Lazy<MenuService> lazy = new Lazy<MenuService>(() => new MenuService());

    public static MenuService Instance { get { return lazy.Value; } }

    private ObservableCollection<MyMenu> myMainMenu;

    public event PropertyChangedEventHandler PropertyChanged;

    private MenuService()
    {
        myMainMenu = new ObservableCollection<MyMenu>();
    }

    public ObservableCollection<MyMenu> MainMenu
    {
        get
        {
            return myMainMenu;
        }
        private set
        {
            myMainMenu = value;
        }
    }
}

В конструкторе модели представления я получаю экземпляр MenuService и добавляю несколько элементов:

private void AddMenuItems()
{
    MyMenu OpenUserLoginMenuItem = new MyMenu
    {
        Header = "_Login",
        Image = "./Icons/IconLogin.png",
        Command = OpenSelectTestprocedureWindowCommand,
        CommandName = "OpenUserLoginDialogCommand"
    };

    MyMenu OpenSelectTestprocedureMenuItem = new MyMenu
    {
        Header = "_Select Testprocedure",
        Image = "./Icons/IconSelectTestprocedure.png",
        Command = OpenSelectTestprocedureWindowCommand,
        CommandName = "OpenSelectTestprocedureWindowCommand"
    };

    MainMenu.Add(OpenUserLoginMenuItem);
    MainMenu.Add(OpenSelectTestprocedureMenuItem);
}

Тогда у меня есть свойство привязки в viewmodel:

public ObservableCollection<MyMenu> MainMenu
{
    get
    {
        return myMenuService.MainMenu;
    }
}

Здесь реализация команды в виде 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);
}

Затем в 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>

Внимание. Тип привязки CommandParameter в xaml в настоящее время неверен. Это еще одна проблема, которую я решу сам. Но для целей тестирования это должно работать. Это даст мне исключение из-за неправильного типа.

Но когда я делаю привязку CommandParameter в Style.Trigger с DataTrigger, свойство CanExecute больше не обновляется во время выполнения. Когда я комментирую этот раздел, все работает отлично. Но тогда у меня нет CommandParameters.

Любая помощь и предложения приветствуются.

1 Ответ

0 голосов
/ 09 февраля 2020

Я нашел проблему.

RelayCommand от mvvm light оценивает тип параметра для функции CanExecute. Это должен быть правильный объявленный тип или нуль.

Так что для целей тестирования мне пришлось установить привязку так:

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