簡體   English   中英

WPF如何根據treeviewitem類型更改contextmenu項?

[英]WPF how to change contextmenu items based on treeviewitem type?

我有一個TreeView項目,我想只為第二層項目彈出ContextMenu 我該怎么做呢?

我假設您將TreeView綁定到項目列表。 如果是這樣,第一和第二層項目是否可以具有不同的數據類型? 然后,您可以為第一層類型執行HierarchicalDataTemplate為第二層類型執行DataTemplate ,如下所示:

<HierarchicalDataTemplate DataType="{x:Type local:FirstTierType}" ItemsSource="{Binding Items}">
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding Name}"  />
    </StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:SecondTierType}">
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding Name}"  />
        <StackPanel.ContextMenu>
            <ContextMenu>
               <MenuItem Header="whatever1" Command="whatever1cmd"></MenuItem>
               <MenuItem Header="whatever2" Command="whatever2cmd"></MenuItem>
               <MenuItem Header="whatever3" Command="whatever2cmd"></MenuItem>
            </ContextMenu>
        </StackPanel.ContextMenu>
    </StackPanel>
</DataTemplate>
.
.
.
<TreeView ItemsSource="{Binding Items}" />

您可以通過混合使用幾個技巧來實現它 - 如果要創建一個IValueConverter,它允許您從HierarchicalDataTemplate內部傳遞FrameworkElement並確定保存當前項目的TreeViewItem是否是頂級TreeViewItem。 這是通過走向wpf應用程序的VisualTree並找到重要的TreeViewItem來實現的。 如果給定的TreeViewItem沒有TreeViewItem類型的祖先,那么您知道它必須是頂級項。 我們可以在Style中使用此信息來設置TreeView項目上的ContextMenu的值。 這是代碼:

XAML:

<Window x:Class="TreeViewContextMenu.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TreeViewContextMenu"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.Resources>
        <local:TreeViewItemToTopLevelConverter x:Key="treeViewConverter"/>
        <ContextMenu x:Key="contextMenu">
            <MenuItem Header="MenuItemHeader"/>
        </ContextMenu>
    </Grid.Resources>
    <TreeView ItemsSource="{Binding Items}">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type local:Part}" ItemsSource="{Binding SubParts}">
                <TextBlock Text="{Binding Name}">
                    <TextBlock.Style>
                        <Style TargetType="TextBlock">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource treeViewConverter}}" Value="False">
                                    <DataTrigger.Setters>
                                        <Setter Property="ContextMenu" Value="{StaticResource contextMenu}"/>
                                    </DataTrigger.Setters>
                                </DataTrigger> 
                            </Style.Triggers>
                        </Style>
                    </TextBlock.Style>
                </TextBlock>
            </HierarchicalDataTemplate>
        </TreeView.Resources>
    </TreeView>
</Grid>

代碼隱藏和ViewModels:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new ViewModel();
    }
}

public class ViewModel : PropertyChangedNotifier
{
    public ViewModel()
    {
        Items = new ObservableCollection<Part>();
        var parent = new Part() { Name = "Parent" };
        parent.SubParts = new ObservableCollection<Part>();
        parent.SubParts.Add(new Part() { Name = "Child1" });
        parent.SubParts.Add(new Part() { Name = "Child2" });

        Items.Add(parent);
    }

    private ObservableCollection<Part> _items;

    public ObservableCollection<Part> Items
    {
        get
        {
            return _items;
        }
        set
        {
            _items = value;
            OnPropertyChanged("Items");
        }
    }
}

public class Part : PropertyChangedNotifier
{
    private string _name;
    private ObservableCollection<Part> _subParts;

    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
            OnPropertyChanged("Name");
        }
    }

    public ObservableCollection<Part> SubParts
    {
        get { return _subParts; }
        set
        {
            _subParts = value;
            OnPropertyChanged("SubParts");
        }
    }

}

public class PropertyChangedNotifier : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public static class VisualTreeTools
{
    public static T GetVisualParent<T>(DependencyObject item) where T : DependencyObject
    {
        while (item != null)
        {
            item = VisualTreeHelper.GetParent(item);
            if (item is T)
                return item as T;
        }

        return null;
    }
}

public class TreeViewItemToTopLevelConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var item = value as DependencyObject;
        if (item == null)
            return 0;

        var containerTreeViewItem = VisualTreeTools.GetVisualParent<TreeViewItem>(item);
        var parentTreeViewItem = VisualTreeTools.GetVisualParent<TreeViewItem>(containerTreeViewItem);

        return parentTreeViewItem == null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM