Несколько значений параметров команды не передаются в модель представления во время множественной привязки

Я вложил элементы меню, ограниченные наблюдаемой коллекцией с именем «CollectionOfAuthors».

Вот иерархия элементов меню: Автор --> ИмяАвтора1 --> ИмяКниги1, ИмяКниги2, ИмяКниги3

Автор — это TopLevelMenuItem, который открывается в списке имен авторов, так что каждое имя автора открывается в списке книг.

При нажатии на каждый элемент меню BookName с помощью команды NavigateToBook я хочу отправить BookName, AuthorName и AuthorID в ViewModel в качестве параметров команды, но я нахожу пустые значения, поскольку (DependencyProperty.UnsetValue) передается в ViewModel.

Нужно знать, какая коррекция требуется?

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

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); } 
} 

Автор.cs

public class Author 
{ 

public string AuthorName { get; set; } 

public string AuthorID { get; set; } 

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

} 

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();
        }
    }

person Mishra Saurabh    schedule 25.07.2018    source источник
comment
реализовать ConvertBack. return value as object[]; наверное достаточно   -  person ASh    schedule 25.07.2018
comment
Есть ошибки привязки?   -  person sTrenat    schedule 25.07.2018
comment
@sTrenat: Нет, я не вижу ошибок привязки.   -  person Mishra Saurabh    schedule 25.07.2018
comment
Кроме того, все значения не установлены?   -  person sTrenat    schedule 25.07.2018
comment
@sTrenat: как предложил АШ, теперь я возвращаюсь - возвращаемое значение как объект []; в методе ConvertBack(). Но улучшений не вижу   -  person Mishra Saurabh    schedule 25.07.2018
comment
Я предполагаю, что внутренняя команда вызывается еще до того, как вы нажмете на пункт меню вашей книги?   -  person sTrenat    schedule 25.07.2018
comment
@sTrenat: Не могли бы вы предоставить дополнительную информацию, чтобы решить эту проблему? Спасибо.   -  person Mishra Saurabh    schedule 26.07.2018
comment
@user42067 user42067 Хм, это странно, я проверил ваш код и .. работает отлично   -  person sTrenat    schedule 26.07.2018
comment
может быть, покажите нам команду RefreshAuthorsList   -  person sTrenat    schedule 26.07.2018
comment
Давайте продолжим обсуждение в чате.   -  person Mishra Saurabh    schedule 26.07.2018


Ответы (1)


Поскольку у вас есть Command в пункте меню верхнего уровня, эта команда попытается вызвать даже до вашей внутренней команды, независимо от того, какое событие должно ее вызвать. В качестве обходного пути вы можете передать свойство IsSubmenuOpen TopMenuItem как CommandParameter и проверить, открыто ли меню, а затем в действии выполнения команды вы можете проверить, открыто ли меню, а затем продолжить или вернуться. Это предотвратит обновление ваших элементов.

CallStack вашей команды:

  • Нажмите на меню книгиЭлемент
  • RefreshListCommand работает
  • элементы обновляются, старые удаляются
  • Связывание пытается получить свойства только что удаленных элементов

Пример решения:

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;
person sTrenat    schedule 26.07.2018