2011-07-29 4 views
0

と私はTreeViewコントロールでユーザーコントロールを持っている、とのContextMenuたDependencyPropertyを持つ:各TreeViewアイテムにContextMenuをバインドするにはどうすればいいですか?

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番目の後に私は明らかに "要素は既に別の要素の子です"例外。

コードビハインドを使わずにバインディングだけで解決できるのですか?

答えて

1

「要素は既に別の要素の子です」と表示されています。 TreeView内のすべてのアイテムは、同じオブジェクト(定義したContextMenu)にバインドされているContextMenusを持っているため例外です。代わりに、あなたが代わりにそのHeirarchicalDataTemplateを公開することができMyControlとでプロパティとしてのContextMenuを露出させる

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

あなたはこの道を行くことを選択した場合、あなたの元のユーザーコントロールの外のTreeView ItemTemplateに定義する必要があります。ユーザーコントロールを使用して外クライアントでは、これを行うことができます:あなたは今、外からユーザーコントロールにTreeViewコントロールのItemTemplateにカスタマイズすることができますので、これはまた、副作用としてユーザーコントロールの柔軟性を高めるよう

<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> 

はそれをやって。一貫して再利用したい場合は、HierarchicalDataTemplateをResourceDictionaryに配置できます。


第2の解決策は、あなたがコードビハインドを使用するために喜んでいる場合は、単に全体のユーザーコントロールのための1のContextMenuを使用して、プログラム的にクライアントの背後にあるコードで選択された項目を決定することです。

<my:MyControl> 
     <my:MyControl.TreeViewItemTemplate> 
      <controlsInputToolkit:ContextMenuService.ContextMenu> 
       <!-- ContextMenu --> 
      </controlsInputToolkit:ContextMenuService.ContextMenu> 
     </my:MyControl.TreeViewItemTemplate> 
    </my:MyControl> 
+0

非常に良いアイデア、ありがとう! – Aaaaaaaa

+0

これは動作しますが、MenuItemsにコマンドをバインドすることはできません: '動作しません。 ElementNameを変更した場合、バインディング例外は発生しません。何か案が? – Aaaaaaaa

+0

あなたには何の例外がありますか?あなたは 'MyMainPage'またはResourceDictionaryでこのバインディングを定義していますか? – fsong

関連する問題