PatrickV
PatrickV

Reputation: 2135

How do I effectively set the DataContext of a StaticResourceExtension

I am trying to reduce code duplication. Consider the following:

<page...>
  <page.resources>
    <MenuItem x:Key="commonItem" />
  </page.resources>
  <TextBlock>
    <TextBlock.ContextMenu>
      <ContextMenu>
        <ContextMenu.Resources>
          <local:thingOne x:Key="one"/>
          <local:thingTwo x:Key="two"/>
        </ContextMenu.Resources>
        <StaticResourceExtension PropertyKey="commonItem"/>
        <StaticResourceExtension PropertyKey="commonItem"/>
      </ContextMenu>
    </TextBlock.ContextMenu>
  </TextBlock>
</page>

How do I pass "one" to the first commonItem instance and "two" to the second?

I realize given the above example there would be a better way to do this, this is an extremely trimmed down version of what is really going on in our XAML.

More generally the question is, how do I follow good DRY principles when I have context menus all over the app that are different, but share some similar menu items?

Upvotes: 0

Views: 151

Answers (2)

PatrickV
PatrickV

Reputation: 2135

So after some research, I realized I was trying to be too complicated. Here is what I did:

Add a custom menu item type:

public class MyMenuItem : MenuItem {}

And in the proper scope context (for me it was global):

<Style TargetType="namespace:MyMenuItem">
    <!-- common control internals -->
</Style>

When it is needed to be used:

<ContextMenu>
    <ContextMenu.Resources>
      <local:thingOne x:Key="one"/>
      <local:thingTwo x:Key="two"/>
    </ContextMenu.Resources>
    <namespace:MyMenuItem DataContext={Binding one}/>
    <namespace:MyMenuItem DataContext={Binding two}/>
</ContextMenu>

This approach allows setting the DataContext and allows for automatic style application when combined with other MenuItems in a MenuBase control that need to have a different behavior.

One would expect a named style could be applied and a simple menu item could be used. I tried that and it did not work. I expect somewhere along the way something was overriding this for a MenuItem, but does not for a MenuItem derived type.

Upvotes: 0

Sphinxxx
Sphinxxx

Reputation: 13017

First, you shouldn't put a MenuItem in your Resources. This will just create a single instance of a MenuItem, and because it's a UIElement it can only be used in one location on your Page.

You could instead keep a Style for a MenuItem in your resources, with all setting that are common to most MenuItems, and apply that style to your items. Tip: If you omit the x:Key from your Style and just give it a TargetType, it will be applied to all MenuItems:

<Page...>
    <Page.resources>
        <Style TargetType="MenuItem" >
            <Setter Property="Header" Value="{Binding}" />
            <Setter Property="Foreground" Value="Lime" />
        </Style>
    </Page.resources>
    <TextBlock>
        <TextBlock.ContextMenu>
            <ContextMenu>
                <ContextMenu.Resources>
                    <local:thingOne x:Key="one"/>
                    <local:thingTwo x:Key="two"/>
                </ContextMenu.Resources>
                <MenuItem DataContext="{StaticResource one}" />
                <MenuItem DataContext="{StaticResource two}" />
            </ContextMenu>
        </TextBlock.ContextMenu>
    </TextBlock>
</Page>

Upvotes: 1

Related Questions