Treeview ContextMenu 将剪切和粘贴绑定到逻辑树

发布于 2024-12-22 08:33:04 字数 4330 浏览 1 评论 0 原文

这似乎是一个非常常见的场景,但我不知道如何在剪贴板中没有任何内容时绑定菜单项以禁用。

我决定不使用 Windows 剪贴板,而是将实际对象存储在 UserControl 上名为 NodeClipboard 的引用变量中。因为它是强类型的并且实现了 INotifyProperty,所​​以它对我来说比 Windows 剪贴板有用得多。

绑定到单个项目可以正常工作,尽管它非常冗长,因为如果不使用样式事件设置器就无法在资源中设置事件处理程序。

它看起来像这样...

<UserControl x:Name="PART_Root">
    <TreeView x:Name="PART_Tree" ItemsSource="{Binding ElementName=PART_Root, Path=RootItemContainer}">
        <TreeView.Resources>
            <ContextMenu x:Key="ContextMenu">
                <ContextMenu.Style>
                    <Style TargetType="ContextMenu">
                        <!-- I use this event to select the tree view item otherwise it is actually pretty difficult to know what item you right clicked on -->
                        <EventSetter Event="Opened" Handler="ContextMenu_Opened"/>
                    </Style>
                </ContextMenu.Style>
                <MenuItem Header="Cut">
                    <MenuItem.Style>
                        <Style TargetType="MenuItem">
                            <EventSetter Event="Click" Handler="CutNode_Click"/>
                            <Style.Triggers>
                                <!-- This binding is fine because it binds to the item that was right clicked on -->
                                <DataTrigger Binding="{Binding Path=IsRoot}" Value="True">
                                    <Setter Property="IsEnabled" Value="False"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </MenuItem.Style>
                </MenuItem>
                <MenuItem Header="Paste">
                    <MenuItem.Style>
                        <Style TargetType="MenuItem">
                            <EventSetter Event="Click" Handler="PasteNode_Click"/>
                            <!-- This binding always fails because ContextMenu lives outside of the logical tree -->
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding ElementName=PART_Root, Path=NodeClipboard" Value="{x:Null}">
                                    <Setter Property="IsEnabled" Value="False"/>
                                </DataTrigger>
                            </Style.Triggers>
                    </Style>
                    </MenuItem.Style>
                </MenuItem>
            </ContextMenu>
            <Style TargetType="TreeViewItem">
                <Setter Property="ContextMenu" Value="{StaticResource ContextMenu}"/>
            </Style>
            <HierarchicalDataTemplate DataType="{x:Type local:Node}" ItemsSource="{Binding Path=Children}">
                <TextBlock Text="{Binding Path=Id}"/>
            </HierarchicalDataTemplate>
        </TreeView.Resources>
    </TreeView>
</UserControl>

不起作用的关键部分是这里:

                        <!-- This binding always fails because ContextMenu lives outside of the logical tree -->
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding ElementName=PART_Root, Path=NodeClipboard" Value="{x:Null}">
                                <Setter Property="IsEnabled" Value="False"/>
                            </DataTrigger>
                        </Style.Triggers>

我尝试使用相对源,这会导致同样的问题。到目前为止,我想到的唯一解决方案是制作两个上下文菜单,一个启用粘贴,一个不启用,然后在 TreeViewItem 样式的 ContextMenu setter 上的样式上切换上下文菜单,如下所示......

<TreeView.Resources>
    <Style TargetType="TreeViewItem">
        <Setter Property="ContextMenu" Value="{StaticResource ContextMenu_PasteEnabled}"/>
        <Style.Triggers>
            <DataTrigger Binding="{Binding ElementName=PART_Root, Path=NodeClipboard" Value="{x:Null}">
                <Setter Property="ContextMenu" Value="{StaticResource ContextMenu_PasteDisabled}"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</TreeView.Resources>

This seems like a pretty common scenario but I can't figure out how to bind the menu items to disable when there is nothing in the clipboard.

I've decided against using the Windows clipboard and instead store the actual object in a reference variable on the UserControl called NodeClipboard. Since it is strongly typed and implements INotifyProperty it is a lot more useful to me than the Windows clipboard.

Binding to the individual item works fine though it is extremely verbose because you can't set EventHandlers within resources without using the Style Event Setters.

It sort of looks like this...

<UserControl x:Name="PART_Root">
    <TreeView x:Name="PART_Tree" ItemsSource="{Binding ElementName=PART_Root, Path=RootItemContainer}">
        <TreeView.Resources>
            <ContextMenu x:Key="ContextMenu">
                <ContextMenu.Style>
                    <Style TargetType="ContextMenu">
                        <!-- I use this event to select the tree view item otherwise it is actually pretty difficult to know what item you right clicked on -->
                        <EventSetter Event="Opened" Handler="ContextMenu_Opened"/>
                    </Style>
                </ContextMenu.Style>
                <MenuItem Header="Cut">
                    <MenuItem.Style>
                        <Style TargetType="MenuItem">
                            <EventSetter Event="Click" Handler="CutNode_Click"/>
                            <Style.Triggers>
                                <!-- This binding is fine because it binds to the item that was right clicked on -->
                                <DataTrigger Binding="{Binding Path=IsRoot}" Value="True">
                                    <Setter Property="IsEnabled" Value="False"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </MenuItem.Style>
                </MenuItem>
                <MenuItem Header="Paste">
                    <MenuItem.Style>
                        <Style TargetType="MenuItem">
                            <EventSetter Event="Click" Handler="PasteNode_Click"/>
                            <!-- This binding always fails because ContextMenu lives outside of the logical tree -->
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding ElementName=PART_Root, Path=NodeClipboard" Value="{x:Null}">
                                    <Setter Property="IsEnabled" Value="False"/>
                                </DataTrigger>
                            </Style.Triggers>
                    </Style>
                    </MenuItem.Style>
                </MenuItem>
            </ContextMenu>
            <Style TargetType="TreeViewItem">
                <Setter Property="ContextMenu" Value="{StaticResource ContextMenu}"/>
            </Style>
            <HierarchicalDataTemplate DataType="{x:Type local:Node}" ItemsSource="{Binding Path=Children}">
                <TextBlock Text="{Binding Path=Id}"/>
            </HierarchicalDataTemplate>
        </TreeView.Resources>
    </TreeView>
</UserControl>

The key part that doesn't work is this here:

                        <!-- This binding always fails because ContextMenu lives outside of the logical tree -->
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding ElementName=PART_Root, Path=NodeClipboard" Value="{x:Null}">
                                <Setter Property="IsEnabled" Value="False"/>
                            </DataTrigger>
                        </Style.Triggers>

I've tried using relative source which results in the same problem. The only solution I've thought of so far is making two context menus, one with Paste enabled and one without, and switching the context menu on the style on the TreeViewItem style's ContextMenu setter like so...

<TreeView.Resources>
    <Style TargetType="TreeViewItem">
        <Setter Property="ContextMenu" Value="{StaticResource ContextMenu_PasteEnabled}"/>
        <Style.Triggers>
            <DataTrigger Binding="{Binding ElementName=PART_Root, Path=NodeClipboard" Value="{x:Null}">
                <Setter Property="ContextMenu" Value="{StaticResource ContextMenu_PasteDisabled}"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</TreeView.Resources>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

睫毛溺水了 2024-12-29 08:33:04

使用剪贴板类。然后您可以使用 ContainsText 方法来确定剪贴板上是否有任何数据。

http://msdn.microsoft.com/en-us /library/system.windows.forms.clipboard.aspx

Use the Clipboard class. Then you can use the ContainsText method to determine if there is any data on the clipboard.

http://msdn.microsoft.com/en-us/library/system.windows.forms.clipboard.aspx

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文