2016-05-10 11 views
0

私はWPF CustomControlsの束を作っているので、これらのコントロールの標準ContextMenuを使用したいので、私はそのContextMenuをリソースとして定義できるかどうかを知りたいと思います。WPF CustomControlsの標準ContextMenuを定義できますか?

このようなContextMenuのスタイルはどのように定義されていますか? ことが可能であるならば、私はそのようなもので、コントロールのコンテキストメニューを上書きすることができます:事前に

ContextMenu="{StaticResource standardcontextmenu}" 

ありがとう!

答えて

2

これは、App.xamlにマージされたXAMLリソース辞書に定義されているため、アプリケーション全体で使用できます。コンテキストメニューをリソースとして定義するのは簡単ですが、リソースの場合は、そのコンテキストが何であるかを知らせるために余分な作業を行う必要があります。ほとんどのWPFコントロールではRelativeSource AncestorTypeバインディングを実行しますが、contextmenuはVisualTreeにはないので動作しません。

It says here that ContextMenu.PlacementTarget will be set to the context menu's ownerメニューが表示されたときにデスクトップにウォッチウィンドウが表示されたら、それについて冗談を言うだけです。

<local:Bar > 
    <local:Bar.ContextMenu> 
     <ContextMenu> 
      <MenuItem 
       Header="{Binding ArbitraryProperty}" 
       /> 
     </ContextMenu> 
    </local:Bar.ContextMenu> 
</local:Bar> 

...しかし、コンテキストメニューがリソースであるときには動作しません:あなたはこのようなコンテキストメニューを定義する場合、そのDataContextlocal:Barのこのインスタンスです。その場合はDataContextを自分で設定する必要があります。それはあまりにもひどく苦痛ではないことが分かります。これはカスタムコントロールのContextMenuOpeningイベントで行います。 2つのカスタムコントロールを定義します。 1つは、をStyleEventSetterで設定し、もう1つでは、ContextMenuOpeningをコンストラクタにラムダで処理します。私はEventSetterバージョンが好きです。もう少し作業している間は、Styleを置くことができる絶対に何かにハンドラを投げることができるからです。そのようなハンドラを設定するために、接続プロパティ/動作を記述することもできます。これはさらに使いやすくなります。

テーマ/ Generic.xaml

<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:SharedContextMenuTest" 
    x:Class="SharedContextMenuTest.Themes.Generic" 
    > 
    <ContextMenu x:Key="SharedContextMenu"> 
     <MenuItem Header="{Binding ArbitraryProperty}" /> 
    </ContextMenu> 

    <Style TargetType="{x:Type local:Foo}"> 
     <!-- IMPORTANT --> 
     <Setter Property="ContextMenu" Value="{StaticResource SharedContextMenu}" /> 
     <EventSetter Event="ContextMenuOpening" Handler="FooBar_ContextMenuOpening" /> 
     <!-- !IMPORTANT --> 

     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="{x:Type local:Foo}"> 
        <Border 
         Background="GhostWhite" 
         BorderBrush="DodgerBlue" 
         BorderThickness="1" 
         Margin="1" 
         > 
         <Label 
          Content="{TemplateBinding ArbitraryProperty}" 
          Padding="20" 
          /> 
        </Border> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 

    <Style TargetType="{x:Type local:Bar}"> 
     <!-- IMPORTANT --> 
     <!-- Bar sets up the ContextMenuOpening handler in its constructor --> 
     <Setter Property="ContextMenu" Value="{StaticResource SharedContextMenu}" /> 
     <!-- !IMPORTANT --> 

     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="{x:Type local:Bar}"> 
        <Border 
         Background="GhostWhite" 
         BorderBrush="ForestGreen" 
         BorderThickness="1" 
         Margin="1" 
         > 
         <Label 
          Content="{TemplateBinding ArbitraryProperty}" 
          Padding="20" 
          /> 
        </Border> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
</ResourceDictionary> 

テーマ/ Generic.xaml.cs

namespace SharedContextMenuTest.Themes 
{ 
    public partial class Generic 
    { 
     private void FooBar_ContextMenuOpening(object sender, ContextMenuEventArgs e) 
     { 
      (e.Source as FrameworkElement).ContextMenu.DataContext = e.Source; 
     } 
    } 
} 

MyCustomControls.cs

namespace SharedContextMenuTest 
{ 
    public class Foo : Control 
    { 
     public static readonly DependencyProperty ArbitraryPropertyProperty = 
      DependencyProperty.Register("ArbitraryProperty", typeof(String), typeof(Foo), 
       new PropertyMetadata(nameof(Foo))); 
    } 

    public class Bar : Control 
    { 
     public Bar() 
     { 
      // Foo has an EventSetter in its Style; here we illustrate a quicker way. 
      ContextMenuOpening += (s, e) => ContextMenu.DataContext = this; 
     } 

     public static readonly DependencyProperty ArbitraryPropertyProperty = 
      DependencyProperty.Register("ArbitraryProperty", typeof(String), typeof(Bar), 
       new PropertyMetadata(nameof(Bar))); 
    } 
} 

MainWindow.xaml

<StackPanel Orientation="Vertical"> 
    <local:Foo /> 
    <local:Bar /> 
</StackPanel> 
+0

こんにちはEd!私はあなたが正しいことを理解したかどうかは分かりません。それは私が各CustomControlのためにそれを定義しなければならないという意味ですか? –

+0

ああ、ちょっとしたことがあります。同じカスタムメニューをたくさん用意しておけば、独自のリソースとして定義することもできます。それに少し戻って、私は私の電話atmにいる。 –

+0

@PatrickPirzerよ、私は今目覚めています。キャッチがあります:共有メニューを定義するのは簡単です。しかし、メニュー項目に何かをバインドするコントロールに何かをバインドすることは絶対的な悪夢です。 WPFの数少ない部分のうちの1つで、ひどくひどく台無しになったものです。 WPFは実際には、コンテキストメニューがそのコンテキストが何であるかを知るのを防ぐのが本当に難しいです。 –

関連する問題