多重绑定期间多个Command参数值未传递到视图模型 [英] Multiple Command parameter values are not getting passed to view-model during multi-binding

查看:54
本文介绍了多重绑定期间多个Command参数值未传递到视图模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我嵌套了菜单项,它们绑定到名为"CollectionOfAuthors"的可观察集合.

I've nested menuitems bounded to observable collection named 'CollectionOfAuthors'.

这是MenuItem层次结构: 作者->作者名1->书名1,书名2,书名3

Here's the MenuItem Hierarchy: Author -->AuthorName1-->BookName1,BookName2,BookName3

作者是TopLevelMenuItem,它在作者名称列表中打开,因此每个作者名称都在图书列表中打开.

Author is TopLevelMenuItem which opens in list of Author names such that each Author name opens into list of Books.

在通过NavigateToBook命令单击每个BookName菜单项时,我想将BookName,AuthorName和AuthorID作为命令参数发送给ViewModel, 但是我发现作为(DependencyProperty.UnsetValue)传递给ViewModel的空值.

While Clicking on each BookName menuitem through NavigateToBook command, I want to send the BookName, AuthorName and AuthorID to ViewModel as command parameters, But I am finding empty values as (DependencyProperty.UnsetValue) passed to ViewModel.

需要知道需要什么更正吗?

Need to know what correction is required?

View.xaml

View.xaml

<Menu>
                            <MenuItem Header="Authors" x:Name="TopLevelMenuItem"
                                      ItemsSource="{Binding CollectionOfAuthors, Mode=TwoWay}">
                                <in:Interaction.Triggers>
                                    <in:EventTrigger EventName="PreviewMouseLeftButtonDown">
                                        <in:InvokeCommandAction Command="{Binding DataContext.RefreshAuthorsList,RelativeSource={RelativeSource AncestorType=Menu}}"/>
                                    </in:EventTrigger>
                                </in:Interaction.Triggers>
                                <MenuItem.ItemTemplate>
                                    <HierarchicalDataTemplate ItemsSource="{Binding Path=Books}">
                                        <StackPanel>
                                            <TextBlock x:Name="tbAuthor" Text="{Binding AuthorName}"/>
                                            <TextBlock x:Name="tbAuthorID" Text="{Binding AuthorID}" Visibility="Collapsed"/>
                                        </StackPanel>
                                        <HierarchicalDataTemplate.ItemTemplate>
                                            <DataTemplate>
                                                <TextBlock x:Name="tbBookName" Text="{Binding}">
                                                    <TextBlock.InputBindings>
                                                        <MouseBinding Command="{Binding DataContext.NavigateToBook, RelativeSource={RelativeSource AncestorType=Menu}}"  MouseAction="LeftClick" >
                                                            <MouseBinding.CommandParameter>
                                                                <MultiBinding Converter="{StaticResource MultiCommandConverter}">
                                                                    <Binding Path="Text" ElementName="tbBookName"/>
                                                                    <Binding Path="DataContext.AuthorName" RelativeSource="{RelativeSource AncestorLevel=2, AncestorType=MenuItem}" />
                                                                    <Binding Path="DataContext.AuthorID" RelativeSource="{RelativeSource AncestorLevel=2, AncestorType=MenuItem}" />
                                                                </MultiBinding>
                                                            </MouseBinding.CommandParameter>
                                                        </MouseBinding>
                                                    </TextBlock.InputBindings>
                                                </TextBlock>
                                            </DataTemplate>
                                        </HierarchicalDataTemplate.ItemTemplate>
                                    </HierarchicalDataTemplate>
                                </MenuItem.ItemTemplate>
                            </MenuItem>
                        </Menu>

ViewModel.cs

ViewModel.cs

public ICommand NavigateToBook
{
   get { return new DelegateCommand(NavigateToBookExecute); }
}

private void NavigateToBookExecute(object obj)
{
     string selectedBookName = ((object[])obj)[0].ToString();
     string selectedAuthorName = ((object[])obj)[1].ToString();
     string selectedAuhorID = ((object[])obj)[2].ToString();           
}

public ICommand RefreshAuthorsList
    {
        get { return new DelegateCommand(RefreshAuthorsListExecute); }
    }


    private void RefreshAuthorsListExecute(object m)
    {
         CollectionOfAuthors = new ObservableCollection<Author>();

           //Here AuthorDetails is another global collection which gets loaded during constructor call
           foreach (var objAuthorItem in AuthorDetails)
           {
               CollectionOfAuthors.Add(new Author
                {
                    AuthorName = objAuthorItem.DisplayName,
                    Books = objAuthorItem.ListOfBooks,
                    AuthorID = objAuthorItem.Id,
                });
           }
    }   

private ObservableCollection<Author> _collectionOfAuthors; 

public ObservableCollection<Author> CollectionOfAuthors 
{ 
 get { return _collectionOfAuthors; } 
 set { SetProperty(ref _collectionOfAuthors, value); } 
} 

Author.cs

Author.cs

public class Author 
{ 

public string AuthorName { get; set; } 

public string AuthorID { get; set; } 

List<string>Books = new List<string>();

} 

MultiCommandConverter.cs

MultiCommandConverter.cs

public class MultiCommandConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            return values.Clone();
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

推荐答案

由于您在顶层菜单项中拥有Command,因此该Command甚至会在内部Command之前尝试调用,因此不会触发任何事件. 作为解决方法,您可以将TopMenuItem的IsSubmenuOpen属性作为CommandParameter传递,并检查Menu是否已打开,然后在Command的执行动作中,您可以检查menu是否已打开,然后继续或返回.这将阻止您的项目被刷新.

Since you have Command at top level menu item, this Command will try to call even before your inner Command, no mather what event should trigger it. As Workaround you could pass IsSubmenuOpen property of TopMenuItem as CommandParameter, and check if Menu is opened, and then in Command's execute action you could check if menu is Opened then continue or return. This will stop your items from being refreshed.

您的命令的CallStack是:

CallStack of your command is:

  • 点击图书菜单项
  • RefreshListCommand运行
  • 项目正在刷新,旧项目已删除
  • 绑定正试图从刚刚删除的项目中获取属性

示例解决方案:

View.xaml

View.xaml

<Menu>
    <MenuItem Header="Authors"  Background="Red" x:Name="TopLevelMenuItem"
                              ItemsSource="{Binding CollectionOfAuthors, Mode=TwoWay}">
        <in:Interaction.Triggers>
            <in:EventTrigger EventName="PreviewMouseLeftButtonDown">
                <in:InvokeCommandAction Command="{Binding DataContext.RefreshAuthorsList,RelativeSource={RelativeSource AncestorType=Menu}}" CommandParameter="{Binding IsSubmenuOpen , ElementName=TopLevelMenuItem}"/>
            </in:EventTrigger>
        </in:Interaction.Triggers>
        <MenuItem.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Path=Books}">
                <StackPanel DataContext="{Binding}">
                    <TextBlock x:Name="tbAuthor" Text="{Binding AuthorName}"/>
                    <TextBlock x:Name="tbAuthorID" Text="{Binding AuthorID}" Visibility="Collapsed"/>
                </StackPanel>
                <HierarchicalDataTemplate.ItemTemplate>
                    <DataTemplate>
                        <TextBlock x:Name="tbBookName" DataContext="{Binding}"  Text="{Binding}">
                                <in:Interaction.Triggers>
                                    <in:EventTrigger EventName="MouseDown">
                                        <in:InvokeCommandAction  Command="{Binding DataContext.NavigateToBook, RelativeSource={RelativeSource AncestorType=Menu}}"  >
                                            <in:InvokeCommandAction.CommandParameter>
                                                <MultiBinding Converter="{StaticResource MultiCommandConverter}">
                                                    <Binding Path="Text" ElementName="tbBookName"/>
                                                    <Binding Path="DataContext.AuthorName" RelativeSource="{RelativeSource AncestorLevel=1, AncestorType=StackPanel}" />
                                                    <Binding Path="DataContext.AuthorID" RelativeSource="{RelativeSource AncestorLevel=1, AncestorType=StackPanel}" />
                                                </MultiBinding>
                                            </in:InvokeCommandAction.CommandParameter>
                                        </in:InvokeCommandAction>
                                    </in:EventTrigger>
                                </in:Interaction.Triggers>
                        </TextBlock>
                    </DataTemplate>
                </HierarchicalDataTemplate.ItemTemplate>
            </HierarchicalDataTemplate>
        </MenuItem.ItemTemplate>
    </MenuItem>
</Menu>

然后在您的RefreshAuthorsListExecute

private void RefreshAuthorsListExecuteExecute(object m)
{
    if ((bool)m)
        return;

这篇关于多重绑定期间多个Command参数值未传递到视图模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆