sckriel
Topic Author
Posts: 6
Joined: 10 Mar 2014, 08:04

Adding context menu using styles/resources

14 Mar 2014, 13:13

Hi All,

I was wondering whether it is possible to give several elements the same ContextMenu by defining it as a static resource and setting it with a style.

Something like this:
<Grid
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
	<Grid.Resources>
		<ContextMenu x:Key="DefaultContextMenu" Background="White">
			<MenuItem Command="ApplicationCommands.Copy" />
			<MenuItem Command="ApplicationCommands.Cut" />
			<MenuItem Command="ApplicationCommands.Paste" />
		</ContextMenu>
		<Style TargetType="{x:Type TextBlock}">
			<Setter Property="ContextMenu" Value="{StaticResource DefaultContextMenu}" />
		</Style>
	</Grid.Resources>
	<StackPanel Orientation="Vertical">
		<TextBlock Text="This is a test"/>
		<TextBlock Text="This is a test"/>
		<TextBlock Text="This is a test"/>
		<TextBlock Text="This is a test"/>
		<TextBlock Text="This is a test"/>
		<TextBlock Text="This is a test"/>
	</StackPanel>
</Grid>
 
User avatar
sfernandez
Site Admin
Posts: 1911
Joined: 22 Dec 2011, 19:20

Re: Adding context menu using styles/resources

14 Mar 2014, 20:53

It should work, but there was a bug. We'll fix it for the next release.
Meanwhile you will have to define the ContextMenu for each element, sorry for the inconvenience.
 
sckriel
Topic Author
Posts: 6
Joined: 10 Mar 2014, 08:04

Re: Adding context menu using styles/resources

17 Mar 2014, 13:46

Thank you!

All the elements that need the context menu are being created programatically. One of a handful of templates are applied. I have tried to include the ContextMenu in the template, but that does not work. (Only a small, empty menu appears).

I then created a context menu for each element in code and then set the context menu's source as a collection of menu items defined as a resource. That failed since the collection can only be used as the source for a single context menu. Could I possibly clone the collection so that it can be applied to every element's context menu?

Or can you suggest some other workaround? I just want to avoid setting up all the menu items in code.
 
User avatar
sfernandez
Site Admin
Posts: 1911
Joined: 22 Dec 2011, 19:20

Re: Adding context menu using styles/resources

18 Mar 2014, 11:34

As it occurs when you define the ContextMenu in a Style, specifying it in a Template won't work because of a bug that will be solved for next release :oops:

If you want to share the same collection along several ItemsControl, you can use a CollectionViewSource:
Collection items = new Collection();
items.Add(new DataItem() { ItemText = "Item1" });
items.Add(new DataItem() { ItemText = "Item2" });
items.Add(new DataItem() { ItemText = "Item3" });
items.Add(new DataItem() { ItemText = "Item4" });
items.Add(new DataItem() { ItemText = "Item5" });
items.Add(new DataItem() { ItemText = "Item6" });
items.Add(new DataItem() { ItemText = "Item7" });
items.Add(new DataItem() { ItemText = "Item8" });
items.Add(new DataItem() { ItemText = "Item9" });

CollectionViewSource cvs1 = new CollectionViewSource();
cvs1.SetSource(items);
contextMenu1.SetItemsSource(cvs1);

CollectionViewSource cvs2 = new CollectionViewSource();
cvs2.SetSource(items);
contextMenu2.SetItemsSource(cvs1);
 
sckriel
Topic Author
Posts: 6
Joined: 10 Mar 2014, 08:04

Re: Adding context menu using styles/resources

24 Mar 2014, 13:41

Thanks. That's exactly what I need. I can't get it to work, though.

I created a custom class, inheriting from Window, with the following in the OnInit() function:
       ParentClass::OnInit();

        Rectangle *rec1;
        Rectangle *rec2;

        rec1 = FindName<Rectangle>("Rectangle1");
        rec2 = FindName<Rectangle>("Rectangle2");

        Ptr<MenuItem> menuItem;
        Ptr<TextBlock> header;
        Ptr<Collection> items = *new Collection();

        menuItem = *new MenuItem();
        header = *new TextBlock("Test1");
        menuItem->SetHeader(header.GetPtr());
        items->Add(menuItem.GetPtr());
        menuItem = *new MenuItem();
        header = *new TextBlock("Test2");
        menuItem->SetHeader(header.GetPtr());
        items->Add(menuItem.GetPtr());
        menuItem = *new MenuItem();
        header = *new TextBlock("Test3");
        menuItem->SetHeader(header.GetPtr());
        items->Add(menuItem.GetPtr());

        Ptr<ContextMenu> contextMenu1 = *new ContextMenu();
        Ptr<ContextMenu> contextMenu2 = *new ContextMenu();
        Ptr<CollectionViewSource> cvs1 = *new CollectionViewSource();
        cvs1->SetSource(items.GetPtr());
        contextMenu1->SetItemsSource(cvs1.GetPtr());
        rec1->SetContextMenu(contextMenu1.GetPtr());

        contextMenu2 = *new ContextMenu();
        Ptr<CollectionViewSource> cvs2 = *new CollectionViewSource();
        cvs2->SetSource(items.GetPtr());
        contextMenu2->SetItemsSource(cvs2.GetPtr());
        rec2->SetContextMenu(contextMenu2.GetPtr()); //Crashes when this line executes
...using the following XAML file...
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="ContextMenuTest"
    Background="Black"
    Width="800" Height="600"
	x:Name="base">
	
	<StackPanel Orientation="Vertical"  Background="Black">
		<Rectangle x:Name="Rectangle1" Fill="Red" Width="200" Height="100" Margin="10"/>
		<Rectangle x:Name="Rectangle2" Fill="Blue" Width="200" Height="100" Margin="10"/>
		<Rectangle x:Name="Rectangle3" Fill="Green" Width="200" Height="100" Margin="10"/>
	</StackPanel>
</Window>
The moment the context menu is set for the second rectangle, an error occurs: "Child already has a logical parent". This is the same error I got when not using the CollectionViewSource.
 
DigitalKarnage
Posts: 22
Joined: 09 Dec 2013, 18:45

Re: Adding context menu using styles/resources

24 Mar 2014, 16:34

The best way around this, is not to create a 'ContextMenu' for each item, but only create 1 ContextMenu. Trap when an item opens it's context menu, handle it, and open the 'custom' context menu you created in it's place. This saves on resources, and allows you to do what your looking for.

If you need an example, let me know, i'll get one up as soon as i can.
 
User avatar
sfernandez
Site Admin
Posts: 1911
Joined: 22 Dec 2011, 19:20

Re: Adding context menu using styles/resources

24 Mar 2014, 17:20

FrameworkElements can only have 1 Logical Parent. If you assign the same MenuItem to different ContextMenu, you will get the error you mentioned.

In my example I was using data items (an ItemTemplate will also be needed), because that way new elements for each ContextMenu are created wrapping the data items, and the Logical Parent limitation is avoided.

Another alternative is, as DigitalKarnage suggested, using the same ContextMenu on different controls.
 
sckriel
Topic Author
Posts: 6
Joined: 10 Mar 2014, 08:04

Re: Adding context menu using styles/resources

25 Mar 2014, 09:18

Thanks for that suggestion DigitalKarnage, I will definitely investigate such an option as my design moves forward.

sfernandez, I finally got it working using ItemTemplates. Thank you!

Who is online

Users browsing this forum: No registered users and 1 guest