1

我有一个 WPF MVVM 应用程序,其中包含TreeView在 XAML 页面中维护的所有静态项目。我如何知道在我的视图模型中单击了哪个 MenuItem,以便我可以相应地显示相应的页面。

    <TreeView Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="MyTreeViewMenu" 
                      VerticalAlignment="Stretch" Width="Auto" Opacity="1" 
                     BorderThickness="1" BorderBrush="Black" Grid.Row="2">

        <TreeViewItem Header="Country" Width="Auto" HorizontalAlignment="Stretch" 
                      ></TreeViewItem>

        <TreeViewItem Header="View Details" Width="Auto" HorizontalAlignment="Stretch" IsEnabled="False">
                <TreeViewItem Header="User" />
                <TreeViewItem Header="Group" />
                <TreeViewItem Header="User Group" />
            </TreeViewItem>
    </TreeView>
4

4 回答 4

4

我想该事件将与您的情况Selected具有相同的效果。click要确定TreeViewItem选择了哪一个,您应该添加 event Trigger

<TreeView Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="MyTreeViewMenu" 
                      VerticalAlignment="Stretch" Width="Auto" Opacity="1" 
                     BorderThickness="1" BorderBrush="Black" Grid.Row="2">

        <TreeViewItem Header="Country" Width="Auto" HorizontalAlignment="Stretch"></TreeViewItem>    
        <TreeViewItem Header="View Details" Width="Auto" HorizontalAlignment="Stretch" IsEnabled="False">
                <TreeViewItem Header="User" />
                <TreeViewItem Header="Group" />
                <TreeViewItem Header="User Group" />
            </TreeViewItem>
               <i:Interaction.Triggers>
                  <i:EventTrigger EventName="SelectedItemChanged">
                      <i:InvokeCommandAction 
                         Command="{Binding selectItemCommand}"
                         CommandParameter="{Binding SelectedItem, ElementName=MyTreeViewMenu}"/>
                  </i:EventTrigger>
              </i:Interaction.Triggers>
</TreeView>

因此,您可以使用并确定通过传递给的参数选择了哪个项目Command

ViewModel应该是这样的:

private ICommand _selectItemCommand;
public ICommand selectItemCommand
{
    get
    {
        return _selectItemCommand ?? (_selectItemCommand = new RelayCommand(param => this.LoadPage(param)));
    }
}

private void LoadPage(object selectedMenuItem)
{
      ...
}
于 2013-08-16T07:50:31.067 回答
2

查看 MSDN 上的TreeView.SelectedItem 属性页。

您可以直接绑定到TreeView.SelectedItem属性:

<TreeView ItemsSource="{Binding Items}" SelectedItem="{Binding Item, Mode=OneWay}" />

请注意,该TreeView.SelectedItem属性是只读的,因此您必须使用OneWay绑定...这意味着您无法从视图模型中设置所选项目。为此,您需要使用Attached Property.

编辑>>>

抱歉@Scroog1,我通常使用 anAttachedProperty来执行此操作。您是对的,即使使用OneWay绑定,使用此方法也会出错。不幸的是,我的AttachedProperty代码很长,但是还有另一种方法可以做到这一点。

我不一定推荐这样做,因为将 UI 属性放入数据对象从来都不是一个好主意,但是如果您将IsSelected属性添加到数据对象,则可以将其直接绑定到TreeViewItem.IsSelected属性:

<TreeView ItemsSource="Items" HorizontalAlignment="Stretch" ... Name="MyTreeViewMenu">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsSelected" Value="{Binding IsSelected}" />
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>

我刚刚在 StackOverflow 上的WPF MVVM TreeView SelectedItem帖子中搜索并为您找到了一个“更全面”的答案。

或者,还有另一种方法......您也可以使用TreeView.SelectedValueandTreeView.SelectedValuePath属性。基本思想是将属性设置为TreeView.SelectedValuePath数据对象上的属性名称。选择一个项目后,该TreeView.SelectedValue属性将设置为所选数据项的该属性的值。您可以从MSDN 上的如何:使用 SelectedValue、SelectedValuePath 和 SelectedItem页面了解有关此方法的更多信息。如果您具有唯一可识别的属性(例如某种标识符),这通常最有效。此代码示例来自 MSDN:

<TreeView ItemsSource="{Binding Source={StaticResource myEmployeeData}, 
XPath=EmployeeInfo}" Name="myTreeView" SelectedValuePath="EmployeeNumber" />

<TextBlock Margin="10">SelectedValuePath: </TextBlock>
<TextBlock Margin="10,0,0,0" Text="{Binding ElementName=myTreeView, 
Path=SelectedValuePath}" Foreground="Blue"/>

<TextBlock Margin="10">SelectedValue: </TextBlock>
<TextBlock Margin="10,0,0,0" Text="{Binding ElementName=myTreeView, 
Path=SelectedValue}" Foreground="Blue"/>
于 2013-08-16T08:06:25.703 回答
0

为了完整起见,这里是附加的属性和 TreeView 子类选项:

附加属性选项

public static class TreeViewSelectedItemHelper
{
    public static readonly DependencyProperty BindableSelectedItemProperty
        = DependencyProperty.RegisterAttached(
            "BindableSelectedItem",
            typeof (object),
            typeof (TreeViewSelectedItemHelper),
            new FrameworkPropertyMetadata(false,
                                          OnSelectedItemPropertyChanged)
                {
                    BindsTwoWayByDefault = true
                });

    public static object GetBindableSelectedItem(TreeView treeView)
    {
        return treeView.GetValue(BindableSelectedItemProperty);
    }

    public static void SetBindableSelectedItem(
        TreeView treeView, 
        object selectedItem)
    {
        treeView.SetValue(BindableSelectedItemProperty, selectedItem);
    }

    private static void OnSelectedItemPropertyChanged(
        DependencyObject sender,
        DependencyPropertyChangedEventArgs args)
    {
        var treeView = sender as TreeView;
        if (treeView == null) return;
        SetBindableSelectedItem(treeView, args.NewValue);
        treeView.SelectedItemChanged -= HandleSelectedItemChanged;
        treeView.SelectedItemChanged += HandleSelectedItemChanged;
        if (args.OldValue != args.NewValue)
            SetSelected(treeView, args.NewValue);
    }

    private static void SetSelected(ItemsControl treeViewItem,
                                    object itemToSelect)
    {
        foreach (var item in treeViewItem.Items)
        {
            var generator = treeViewItem.ItemContainerGenerator;
            var child = (TreeViewItem) generator.ContainerFromItem(item);
            if (child == null) continue;
            child.IsSelected = (item == itemToSelect);
            if (child.HasItems) SetSelected(child, itemToSelect);
        }
    }

    private static void HandleSelectedItemChanged(
        object sender,
        RoutedPropertyChangedEventArgs<object> args)
    {
        if (args.NewValue is TreeViewItem) return;
        var treeView = sender as TreeView;
        if (treeView == null) return;
        var binding = BindingOperations.GetBindingExpression(treeView,
            BindableSelectedItemProperty);
        if (binding == null) return;
        var propertyName = binding.ParentBinding.Path.Path;
        var property = binding.DataItem.GetType().GetProperty(propertyName);
        if (property != null)
            property.SetValue(binding.DataItem, treeView.SelectedItem, null);
    }
}

子类选项

public class BindableTreeView : TreeView
{
    public BindableTreeView()
    {
        SelectedItemChanged += HandleSelectedItemChanged;
    }

    public static readonly DependencyProperty BindableSelectedItemProperty =
        DependencyProperty.Register(
            "BindableSelectedItem",
            typeof (object),
            typeof (BindableTreeView),
            new FrameworkPropertyMetadata(
                default(object),
                OnBindableSelectedItemChanged) {BindsTwoWayByDefault = true});

    public object BindableSelectedItem
    {
        get { return GetValue(BindableSelectedItemProperty); }
        set { SetValue(BindableSelectedItemProperty, value); }
    }

    private static void OnBindableSelectedItemChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        var treeView = d as TreeView;
        if (treeView != null) SetSelected(treeView, e.NewValue);
    }

    private static void SetSelected(ItemsControl treeViewItem,
                                    object itemToSelect)
    {
        foreach (var item in treeViewItem.Items)
        {
            var generator = treeViewItem.ItemContainerGenerator;
            var child = (TreeViewItem) generator.ContainerFromItem(item);
            if (child == null) continue;
            child.IsSelected = (item == itemToSelect);
            if (child.HasItems) SetSelected(child, itemToSelect);
        }
    }

    private void HandleSelectedItemChanged(
        object sender,
        RoutedPropertyChangedEventArgs<object> e)
    {
        SetValue(BindableSelectedItemProperty, SelectedItem);
    }
}
于 2013-08-16T14:30:20.633 回答
0

除了绑定到 TreeView.SelectedItem 属性:

在使用 MVVM 时,它帮助我停止思考 UI 中的事件并开始思考 UI 中的状态。

您可以将 ViewModel 绑定到 View 的属性。所以一般来说,我尝试将 SelectedItem 绑定到 ViewModel 上的属性,以便 ViewModel 知道选择了什么。

以同样的方式,您可以向正在显示的 ViewModel 项目添加一个名为 Selected 的属性,并将此属性绑定到视图中的复选框。这样您就可以在 ViewModel 中启用多项选择并轻松访问所选项目。

于 2013-08-16T09:05:35.057 回答