0

そして、TreeView と ContextMenu DependencyProperty を持つ UserControl があります。

    public ObservableCollection<Control> ContextMenu {
        get {
            return ( ObservableCollection<Control> )GetValue( ContextMenuProperty );
        }
        set {
            SetValue( ContextMenuProperty, value );
        }
    }

    public static readonly DependencyProperty ContextMenuProperty =
        DependencyProperty.Register( "ContextMenu", typeof( ObservableCollection<Control> ), typeof( FilterableTreeViewControl ),
        new PropertyMetadata( new ObservableCollection<Control>(), new PropertyChangedCallback( FilterableTreeViewControl.OnContextMenuPropertyChange ) ) );

    private static void OnContextMenuPropertyChange( DependencyObject d, DependencyPropertyChangedEventArgs e ) {
        FilterableTreeViewControl ctrl = d as FilterableTreeViewControl;
        ctrl.OnContextMenuChange( ( Object )e.NewValue );
    }

    protected virtual void OnContextMenuChange( Object NewItemsSource ) {
    }

XAML:

        <controlsToolkit:TreeViewDragDropTarget AllowDrop="True" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Drop="TreeViewDragDropTarget_Drop" AllowedSourceEffects="All">
            <controlsToolkit:TreeViewDragDropTarget.Resources>
                <Data:HierarchicalDataTemplate x:Key="TreeViewTemplate" ItemsSource="{Binding Children}">
                    <StackPanel Orientation="Horizontal" Height="Auto" Width="Auto">
                        <Image Source="{Binding Type,Converter={StaticResource TreeIconConverter}}" />
                        <TextBlock x:Name="NameTextBlock" Text="{Binding Name}">
                            <controlsInputToolkit:ContextMenuService.ContextMenu>
                                <controlsInputToolkit:ContextMenu ItemsSource="{Binding ElementName=MyTreeViewControl, Path=ContextMenu}" />
                            </controlsInputToolkit:ContextMenuService.ContextMenu>
                        </TextBlock>
                    </StackPanel>
                </Data:HierarchicalDataTemplate>
            </controlsToolkit:TreeViewDragDropTarget.Resources>
            <Controls:TreeView Name="treeView" ItemTemplate="{StaticResource TreeViewTemplate}">
            </Controls:TreeView>
        </controlsToolkit:TreeViewDragDropTarget>

使用法:

        <my:MyControl
                DragEnabled="False"
                ItemsSource="{Binding TreeRootNodes}" 
                FilterCaption="Filter:" 
                SelectionChangedCommand="{Binding SelectedMachineGroupChangedCommand_L}"
                DropCommand="{Binding DropCommand}">
            <my:FilterableTreeViewControl.ContextMenu>
                <controlsInputToolkit:MenuItem Header="Menu 1" />
                <controlsInputToolkit:MenuItem Header="Menu 2" />
                <controlsInputToolkit:MenuItem Header="Menu 3" />
            </my:MyControl.ContextMenu>
        </my:MyControl>

最初はすべてうまくいきますが、2回目以降は明らかに「要素はすでに別の要素の子です」というメッセージが表示されます。例外。

コードビハインドなしで、バインディングだけでそれを解決することは可能ですか?

4

1 に答える 1

1

「要素はすでに別の要素の子です」というメッセージが表示されます。TreeView 内のすべてのアイテムの ContextMenus が同じオブジェクト (で定義した ContextMenu) にバインドされているため、例外が発生します。

ContextMenu を MyControl のプロパティとして公開する代わりに、その HeirarchicalDataTemplate を公開できます。

public HeirarchicalDataTemplate TreeViewItemTemplate {
    get {
        return (HeirarchicalDataTemplate)this.treeView.ItemTemplate; 
    }
    set {
        this.treeView.ItemTemplate = value;
    }
}

この方法を選択した場合は、元のユーザー コントロールの外部で TreeView ItemTemplate を定義する必要があります。UserControl を使用する外部クライアントでは、次のことができます。

    <my:MyControl>
        <my:MyControl.TreeViewItemTemplate>
            <Data:HierarchicalDataTemplate>
                   <!-- Rest of the template -->
                    <TextBlock x:Name="NameTextBlock" Text="{Binding Name}">
                        <controlsInputToolkit:ContextMenuService.ContextMenu>
                            <!-- ContextMenu -->
                        </controlsInputToolkit:ContextMenuService.ContextMenu>
                    <!-- Rest of the template -->
            </Data:HierarchicalDataTemplate>
        </my:MyControl.TreeViewItemTemplate>
    </my:MyControl>

このようにすることで、UserControl の TreeView の ItemTemplate を外部からカスタマイズできるようになったため、副作用として UserControl の柔軟性も向上します。一貫して再利用したい場合は、HierarchicalDataTemplate を ResourceDictionary に配置できます。


コード ビハインドを使用する場合の 2 番目の解決策は、UserControl 全体に対して 1 つの ContextMenu を使用し、クライアントのコード ビハインドでどの項目が選択されたかをプログラムで判断することです。

    <my:MyControl>
        <my:MyControl.TreeViewItemTemplate>
            <controlsInputToolkit:ContextMenuService.ContextMenu>
                <!-- ContextMenu -->
            </controlsInputToolkit:ContextMenuService.ContextMenu>
        </my:MyControl.TreeViewItemTemplate>
    </my:MyControl>
于 2011-07-29T22:45:54.840 に答える