WPF ControlTemplate for nesting - wpf

I want to create a Template for my ContextMenu, which I can reuse as a child for some of my ContextMenu entries:
<ControlTemplate x:Name="StatusContextMenu" x:Key="StatusContextMenu">
<MenuItem>
<MenuItem Header="BLA" />
</MenuItem>
</ControlTemplate>
<ContextMenu x:Shared="false" x:Key="SysTrayMenu">
<MenuItem Header="Online" Command="{Binding SetStatusOnlineCommand}" Template="{StaticResource StatusContextMenu}" />
<MenuItem Header="Away" Command="{Binding SetStatusAbwesendCommand}" Template="{StaticResource StatusContextMenu}" />
</ContextMenu>
Using the ControlTemplate my Headers are empty, but at least every MenuItem has the "Bla"-Child ... I want to achieve this structure:
- Online
- Bla
- Away
- Bla
I will replace "Bla" with the last 10 statustext for the specific status. AND a textbox at the top to set a new statustext.
The statustexts will differ for Online and Away.
Everything is declared inside a ResourceDictionary
My Question is:
How to create a template to reuse in XAML several times?!

Related

wpf extend contextmenu of textbox

I am searching for a way to extend the contextmenu of a textbox. I know there are dozens of solutions out there that recreate the contextmenu as a whole, but how on earth can I simply add one custom entry to a existing context menu?
Thanks
Klaus
<TextBox>
<TextBox.ContextMenu>
<ContextMenu>
<MenuItem Command="ApplicationCommands.Cut" />
<MenuItem Command="ApplicationCommands.Copy" />
<MenuItem Command="ApplicationCommands.Paste" />
<MenuItem Command="ApplicationCommands.SelectAll" />
//Your own item here
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
Please not that all command are automatically operation and will work as expected

How to apply a custom style context menu for TextBox (default context menu copy/cut/paste)?

I create style for the MenuItem.
When I create my own menu, everything is good.
But how can I apply a style to the context menu of TextBox?
I mean, the menu (Copy, Cut, Paste, etc.) - I do not want to create new lines, and just change the style.
//My Custom Menu Example
<UserControl.ContextMenu>
<ContextMenu Style="{StaticResource ContextMenuStyle}" HasDropShadow="True">
<MenuItem x:Name="MenuItem1" Header="Open"
Style="{StaticResource ContextMenuItem}">
</MenuItem>
<MenuItem x:Name="MenuItem2" Header="Save"
Style="{StaticResource ContextMenuItem}">
</MenuItem>
<MenuItem x:Name="MenuItem3" Header="Delete"
Style="{StaticResource ContextMenuItem}">
</MenuItem>
</ContextMenu>
</UserControl.ContextMenu>
You will technically have to to do the same thing you did to your UserControl.ContextMenu to the TextBox.ContextMenu.
Look the below link which has exactly the scenario you are asking about with xaml.

Dynamically binding to ViewModel commands on Window's MenuItem

Working on a WPF application using the MVVM structure.
My Window displays a menu and the current ViewModel. On one of the Menu's MenuItems, I want to list some Commands found in the current ViewModel. The commands listed in the Menu will change depending on the ViewModel.
I got this to work just fine, but the style is messed up - the Command MenuItems are inside another menu box or something. I'll attach a screenshot.
I wrapped the ViewModel's ICommand objects (RelayCommands, in this instance) in CommandViewModel, which expose the Command and the Display string I want on the menu. These CommandViewModels are in a list: CurrentWorkspace.AdditionalOptionsCommands.
Here is the XAML for the Menu. Like I said, it works, it shows the right items and the commands are executed. The display is just incorrect - can anybody tell me why and how to fix it? See the screenshot.
<Menu>
<MenuItem Header="_Additional Options..." ItemsSource="{Binding Path=CurrentWorkspace.AdditionalOptionsCommands}">
<MenuItem.ItemTemplate>
<DataTemplate DataType="{x:Type vm:CommandViewModel}">
<MenuItem Header="{Binding Path=DisplayText}" Command="{Binding Path=Command}"/>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
<MenuItem Header="_Testing">
<MenuItem Header="This looks right" />
<MenuItem Header="This looks right" />
</MenuItem>
</Menu>
Current Appearance:
Desired Appearance:
This is because when you specify menu items via ItemsSource each item gets automatically wrapped into a MenuItem object. This way the content defined in the DataTemplate (MenuItem element) gets wrapped into one more MenuItem.
What you need to do instead of defining a DataTemplate is to define a style for the MenuItem where you setup bindings to the view model's properties and use this style as ItemContainerStyle on the parent MenuItem:
<Window.Resources>
<Style x:Key="CommandMenuItemStyle"
TargetType="{x:Type MenuItem}">
<Setter Property="Header"
Value="{Binding Path=DisplayText}"/>
<Setter Property="Command"
Value="{Binding Path=Command}"/>
</Style>
</Window.Resources>
...
<Menu>
<MenuItem Header="_Additional Options..."
ItemsSource="{Binding Path=CurrentWorkspace.AdditionalOptionsCommands}"
ItemContainerStyle="{StaticResource CommandMenuItemStyle}"/>
<MenuItem Header="_Testing">
<MenuItem Header="This looks right" />
<MenuItem Header="This looks right" />
</MenuItem>
</Menu>
See http://drwpf.com/blog/2008/03/25/itemscontrol-i-is-for-item-container/ for an in-depth explanation on how item containers work with ItemsControl controls.

Images in XAML ResourceDictionary disappear on ToolBar when Menu opens

I have started to move various common Images into a ResourceDictionary and noticed an odd behavior in my WPF application. If the Image is used in a MenuItem and in a Button on a ToolBar, when I open the Menu the image disappears on the Button.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Image x:Key="NewImage"
Source="/SomeApplication;component/Resources/NewDocumentHS.png"
Stretch="None"/>
<!-- ... -->
Relevant XAML from the Window:
<Menu>
<MenuItem Header="_File">
<MenuItem Header="_New"
Command="{Binding NewCommand}"
Icon="{DynamicResource NewImage}" />
<!-- ... -->
<ToolBarTray>
<ToolBar>
<Button Command="{Binding NewCommand}"
Content="{DynamicResource NewImage}" />
I assume this is a caveat of resources in a ResourceDictionary, but I am unable to discover the appropriate fix for this. Behavior occurs with both StaticResource and DynamicResource. It also doesn't appear to be affected by if the ResourceDictionary stands on its own or if it is merged with others. No other resource shares that key either.
Edit: Additionally, adding PresentationOptions:Freeze="True" to the images did not change the situation.
The Image class is a visual, so it can only appear in the visual tree in one location. Therefore, you cannot share it among multiple MenuItems/Buttons/etc.
You can however share the ImageSource (i.e. Image.Source) value.
In WPF, I believe you can use x:Shared="False" to force WPF to create a new instance for each request though.
You cannot use an Image control in multiple places, it can only be appear in the Visual Tree at one place, so if the call to the resource is made the image is being snatched from the previous owner.
Edit: x:Shared="False" Is obviously a better solution than all of my suggestions below, i wonder why such an important property does not show up in the Intellisense -_-
This behaviour is a bit of a pain, i normally use to predefine a IconStyle and the BitmapImages for the Source of the images but create new Images for every MenuItem where i might need it.
You can also create a DataTemplate for your Icon:
Resources:
<Style x:Key="IconImageStyle" TargetType="{x:Type Image}">
<Setter Property="MaxWidth" Value="16"/>
<Setter Property="MaxHeight" Value="16"/>
</Style>
<DataTemplate x:Key="Icon_Close_Template">
<Image Style="{StaticResource IconImageStyle}"
Source="pack://application:,,,/Images/Close.ico"/>
</DataTemplate>
Usage:
<Menu>
<MenuItem Header="File">
<MenuItem Header="Close">
<MenuItem.Icon>
<ContentPresenter ContentTemplate="{StaticResource Icon_Close_Template}"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Close">
<MenuItem.Icon>
<ContentPresenter ContentTemplate="{StaticResource Icon_Close_Template}"/>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</Menu>
Since templates are created via factories this will work, still significantly inflates the XAML though...
To get around this you could for example write a markup extension, this one is very simple and only copies the values of the Source and Style properties, you could also use reflection or other means to create a complete copy:
[MarkupExtensionReturnType(typeof(object))]
public class IconExtension : MarkupExtension
{
private Image icon;
public Image Icon
{
get { return icon; }
set { icon = value; }
}
public IconExtension() { }
public IconExtension(Image icon)
{
Icon = icon;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (Icon == null) throw new ArgumentNullException("Icon");
return new Image() { Source = Icon.Source, Style = Icon.Style };
}
}
Can be used like this:
<Style x:Key="IconImageStyle" TargetType="{x:Type Image}">
<Setter Property="MaxWidth" Value="16"/>
<Setter Property="MaxHeight" Value="16"/>
</Style>
<Image x:Key="Icon_Close" Style="{StaticResource IconImageStyle}" Source="pack://application:,,,/Images/Close.ico"/>
<!-- ... -->
<MenuItem Header="File">
<MenuItem Header="Close" Icon="{m:Icon {StaticResource Icon_Close}}"/>
<MenuItem Header="Close" Icon="{m:Icon {StaticResource Icon_Close}}"/>
</MenuItem>

Why can't I use the same Icon for more than 1 item in Menu?

I have a MenuItem like below
<MenuItem Header="Edit">
<MenuItem Header="Copy Direct Link" Icon="{StaticResource CopyIcon}" Command="{Binding CopyImageCommand}" />
<MenuItem Header="Copy Image Data" Icon="{StaticResource CopyIcon}" Command="{Binding CopyImageDataCommand}" />
<MenuItem Header="Paste" Icon="{StaticResource PasteIcon}" Command="{Binding PasteImageCommand}" />
</MenuItem>
Notice the 1st 2 items use the same icon, I get something like below
I tried removing the 2nd item,
<MenuItem Header="Edit">
<MenuItem Header="Copy Direct Link" InputGestureText="Ctrl+C" Icon="{StaticResource CopyIcon}" Command="{Binding CopyImageCommand}" />
<!--<MenuItem Header="Copy Image Data" InputGestureText="Ctrl+Alt+C" Icon="{StaticResource CopyIcon}" Command="{Binding CopyImageDataCommand}" />-->
<MenuItem Header="Paste" InputGestureText="Ctrl+P" Icon="{StaticResource PasteIcon}" Command="{Binding PasteImageCommand}" />
</MenuItem>
then I got something like
How can I reuse Icons?
See this question
An Image can only have one parent so it will be moved from the first MenuItem to the second. You can add the x:Shared attribute like this
<Window.Resources>
<Image x:Key="CopyIcon" x:Shared="False" Source="..." />
</Window.Resources>
From msdn
x:Shared Attribute
When set to false, modifies WPF
resource-retrieval behavior so that
requests for the attributed resource
create a new instance for each request
instead of sharing the same instance
for all requests.
You're most likely declaring CopyIcon as Image type in your resource, something like this:
<Window.Resources>
<Image x:Key="CopyIcon" Source="yourcopyicon.ico"/>
</Window.Resources>
So, the root cause of the problem is, Image is a visual element, since it derives from FrameworkElement (which is a visual element), and a visual element cannot have more than one parent at the same time. That is why the first MenuItem is not showing the icon, since the second MenuItem reset the parent of CopyIcon, making itself parent of the CopyIcon.
Hope this explanation is helpful to you. Now follow what Meleak has said in his response. :-)
Try the following:
<MenuItem Header=“Paste“ >
<MenuItem.Icon><Image Height=“16“ Width=“16“ Source=“paste.jpg“ /></MenuItem.Icon>
</MenuItem>

Resources