WPF: TreeViewItem привязан к ICommand - PullRequest
       44

WPF: TreeViewItem привязан к ICommand

9 голосов
/ 15 февраля 2010

Я занят созданием моего первого приложения MVVM в WPF.

В основном проблема, с которой я сталкиваюсь, состоит в том, что у меня есть TreeView (System.Windows.Controls.TreeView), который я поместил в свое окно WPF. Я решил, что я буду привязывать к ReadOnlyCollection элементов CommandViewModel и этих элементов состоят из DisplayString, Tag и RelayCommand.

Теперь в XAML у меня есть TreeView, и я успешно привязал свою коллекцию ReadOnlyCollection к этому. Я могу просмотреть это, и все выглядит хорошо в пользовательском интерфейсе.

Проблема теперь в том, что мне нужно связать RelayCommand с Командой TreeViewItem, однако из того, что я вижу, TreeViewItem не имеет Команды. Это заставляет меня делать это в свойстве IsSelected или даже в коде метода TreeView_SelectedItemChanged, или есть способ сделать это волшебным образом в WPF?

Это код, который у меня есть:

<TreeView BorderBrush="{x:Null}" 
      HorizontalAlignment="Stretch" 
      VerticalAlignment="Stretch">
<TreeView.Items>
    <TreeViewItem
        Header="New Commands"
        ItemsSource="{Binding Commands}"
        DisplayMemberPath="DisplayName"
        IsExpanded="True">
    </TreeViewItem>
</TreeView.Items>

и в идеале я хотел бы просто пойти:

<TreeView BorderBrush="{x:Null}" 
      HorizontalAlignment="Stretch" 
      VerticalAlignment="Stretch">
<TreeView.Items>
    <TreeViewItem
        Header="New Trade"
        ItemsSource="{Binding Commands}"
        DisplayMemberPath="DisplayName"
        IsExpanded="True"
        Command="{Binding Path=Command}">
    </TreeViewItem>
</TreeView.Items>

Есть ли у кого-нибудь решение, позволяющее мне использовать имеющуюся у меня инфраструктуру RelayCommand.

Спасибо, ребята, очень ценю!

Richard

Ответы [ 5 ]

24 голосов
/ 04 февраля 2011

Я знаю, что это было "ответом" некоторое время назад, но так как ответы не были идеальными, я решил, что я положу свои два цента. Я использую метод, который позволяет мне не прибегать к какой-либо «хитрой стилизованной кнопке» или даже использовать код позади и вместо этого сохраняет все мое разделение в MVVM. В вашем TreeView добавьте следующий xaml:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="SelectedItemChanged">
        <i:InvokeCommandAction Command="{Binding TreeviewSelectedItemChanged}" CommandParameter="{Binding ElementName=treeView, Path=SelectedItem}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

В заголовке xaml добавьте:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

и тогда вам нужно будет добавить ссылку на вышеуказанную сборку в вашем проекте.

После этого все действует так же, как любая другая команда, скажем, кнопка или что-то в этом роде.

2 голосов
/ 15 февраля 2010

Спасибо за вклад в проблему, и да, я действительно сказал, что не хочу решения, стоящего за Кодексом, однако в то время у меня все еще было сильное впечатление, что я просто что-то упустил ... так что яв конечном итоге с помощью события TreeView_SelectedItemChanged.

Несмотря на то, что подход Уилла выглядит неплохо, для моей личной ситуации я решил, что буду использовать код позади.Причина этого в том, что View и XAML останутся такими, какими они были бы, если бы TreeViewItem имел свойство «Command», к которому могла быть привязана моя команда.Теперь мне не нужно менять шаблоны или представления, все, что мне нужно сделать, это добавить код и событие для TreeView_SelectedItemChanged.

Мое решение:

  private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        if (sender != null)
        {
            var treeView = sender as TreeView;
            if (treeView != null)
            {
                var commandViewModel = treeView.SelectedItem as CommandViewModel;
                if (commandViewModel != null)
                {
                    var mi = commandViewModel.Command.GetType().GetMethod("Execute");
                    mi.Invoke(commandViewModel.Command, new Object[] {null});
                }
            }
        }
    }

Как я уже сделалпривязав RelayCommand к TreeViewItem, все, что я сейчас делаю, это просто вручную вызываю метод «Execute» для этой конкретной RelayCommand.

Если это абсолютно неправильный способ, пожалуйста, дайте мне знать ...

Спасибо!

1 голос
/ 15 февраля 2010

Что бы я сделал, это установил Заголовок TreeViewItem как кнопку, затем обработал кнопку, чтобы она не выглядела или не действовала как единое целое, затем выполните привязку моей команды к кнопке ,

Возможно, вам потребуется сделать это через DataTemplate, или вам может понадобиться изменить шаблон самого TreeViewItem. Никогда не делал этого, но вот как я делал подобные вещи (например, заголовки вкладок).


Вот пример того, о чем я говорю (вы можете оставить это в Kaxaml и поиграть с этим):

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   <Page.Resources>
      <Style x:Key="ClearButan" TargetType="Button">
         <Setter Property="Template">
            <Setter.Value>
               <ControlTemplate TargetType="Button">              
                 <Border Name="border"
                     Padding="4"
                     Background="transparent">
                     <Grid >
                     <ContentPresenter HorizontalAlignment="Center"
                                    VerticalAlignment="Center">
                     </ContentPresenter>
                     </Grid>
                 </Border>
               </ControlTemplate>
            </Setter.Value>
         </Setter>
      </Style>
   </Page.Resources>
   <Grid>
      <TreeView>
         <TreeViewItem>
            <Button Style="{StaticResource ClearButan}">
            easy peasy
            </Button>
         </TreeViewItem>
      </TreeView>
   </Grid>
</Page>

Я создал новый прозрачный стиль для кнопки. Затем я просто опускаю кнопку в TVI и устанавливаю ее стиль. Конечно, вы можете сделать то же самое, используя шаблоны данных.

0 голосов
/ 16 ноября 2018

Я улучшаю хорошее решение от Ричарда через общее свойство Tag:

MyView.xaml:

 <TreeView SelectedItemChanged="TreeView_SelectedItemChanged" Tag="{Binding SelectTreeViewCommand}" >
                  <TreeViewItem Header="Item1" IsExpanded="True"   Tag="Item1"  />
                  <TreeViewItem Header="Item2" IsExpanded="True">
                      <TreeViewItem Header="Item21"  Tag="Item21"/>
                  </TreeViewItem>
              </TreeView>

MyView.xaml.cs

    private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        var treeView = (TreeView)sender;
        var command = (ICommand)treeView.Tag;
        TreeViewItem selectedItem = (TreeViewItem)treeView.SelectedItem;
        if (selectedItem.Tag != null)
        {
            command.Execute(selectedItem.Tag);
        }
    }

MyViewModel.cs

      public RelayCommand selectTreeViewCommand;
      [Bindable(true)]
      public RelayCommand SelectTreeViewCommand => selectTreeViewCommand ?? (selectTreeViewCommand = new RelayCommand(CanSelectTreeViewCommand, ExecuteSelectTreeViewCommand));

      private void ExecuteSelectTreeViewCommand(object obj)
      {
          Console.WriteLine(obj);
      }

      private bool CanSelectTreeViewCommand(object obj)
      {
          return true;
      }
0 голосов
/ 15 февраля 2010

Это хороший пример того, как MVVM очень запоздалая мысль в WPF. Вы ожидаете, что будет командная поддержка определенных элементов графического интерфейса, но ее нет, поэтому вы вынуждены пройти сложный процесс (как показано в примере Уилла) только для того, чтобы присоединить команду к чему-либо.

Будем надеяться, что они решат эту проблему в WPF 2.0: -)

...