Visual brush as an icon in the ContextMenu wpf - c#

I want to use Visual Brush as an icon in the context menu (of treeview) in my wpf usercontrol.
I have a resource dictionary (separate icon xaml file), few lines from the file are given below:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<VisualBrush x:Key="Trashcan"
Stretch="Uniform">
I have merged the dictionaries in the usercontrol, and also checked that it has been added and can be accessed in the usercontrol xaml code.
The code in the usercontrol xaml (view) is given below, where the icons have to be used
<ContextMenu x:Key=xxxxxxxx>
<MenuItem Header="Delete" Command="{Binding xxxxxx, Source=xxxxxxx}" CommandParameter="{Binding}" IsEnabled="xxxxxxxxxx}" Icon="{StaticResource Trashcan}"/>
</ContextMenu>
Now the issue is I am unable to see the icons in the context menu, picture is attached below:
So far, I have tried the approach given in this link Using MahApps Icons with ContextMenu but didnt quite work for me.
Is there some way other than the one in the above mentioned link that could be used to show visual brush as an icon in the context menu.
NOTE: I cannot use the menuitem.icon -> image, as I have restrictions coming from other components of the application.
NOTE: I dont know whether it is important to state here that a Form is hosting my WPF usercontrol.

What you need is to set an Image to the MenuItem.Icon.
<MenuItem.Icon>
<Image Style="{StaticResource Trashcan}"/>
</MenuItem.Icon>
Define a style for that image in the resource dictionary:
<Style x:Key="Trashcan" TargetType="Image">
<Setter Property="Source" Value="/ProjectName;component/Images/Trashcan.png"/>
<Setter Property="Width" Value="24"/>
</Style>
added:
If you can't use MenuItem.Icon here's a trick you can do:
<MenuItem.Header>
<Grid>
<TextBlock Text="........"/>
<Image HorizontalAlignment="Left" Width="24" Margin="-24,0,0,0"
Style="{StaticResource Trashcan}"/>
</Grid>
</MenuItem.Header>

Related

How do I align the Keyboard accelerator text to the right in UWP?

<Grid>
<Button Content="Button1">
<Button.Flyout>
<MenuFlyout>
<MenuFlyoutItem Text="Item 1">
<MenuFlyoutItem.KeyboardAccelerators>
<KeyboardAccelerator Key="Number1" Modifiers="Control"/>
</MenuFlyoutItem.KeyboardAccelerators>
</MenuFlyoutItem>
<MenuFlyoutItem Text="Item 2">
<MenuFlyoutItem.KeyboardAccelerators>
<KeyboardAccelerator Key="Number2" Modifiers="Control,Menu"/>
</MenuFlyoutItem.KeyboardAccelerators>
</MenuFlyoutItem>
</MenuFlyout>
</Button.Flyout>
</Button>
</Grid>
The keyboard accelerator text is aligned to the left as shown in the image below:
Is there anyway I can align the keyboard accelerator text to the right as shown in the Google chrome menu?
The KeyboardAccelerator have a content presenter in the style of MenuFlyoutItem, so we could change the default style of MenuFlyoutItem to adjust the text location of KeyboardAccelerator. Please refer to the following steps.
Open generic.xaml, find the default MenuFlyoutItem style whose key is MenuFlyoutItemRevealStyle, copy this style and paste to App.xaml. Besides, you also need to add <Style TargetType="MenuFlyoutItem" BasedOn="{StaticResource MenuFlyoutItemRevealStyle}" /> to App.xaml, which will apply this style for all MenuFlyoutItem.
Then you will find a TextBlock named KeyboardAcceleratorTextBlock in MenuFlyoutItemRevealStyle, you could add TextAlignment="Right" to this TextBlock.
As follows:
<Application
..>
<Application.Resources>
<ResourceDictionary>
<Style TargetType="MenuFlyoutItem" BasedOn="{StaticResource MenuFlyoutItemRevealStyle}" />
<Style TargetType="MenuFlyoutItem" x:Key="MenuFlyoutItemRevealStyle">
…….
<TextBlock x:Name="KeyboardAcceleratorTextBlock"
……
TextAlignment="Right"
AutomationProperties.AccessibilityView="Raw" />
……
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
You can refer the all and some new control in the XAML Control Gallery, search this application on the Microsoft store and we will get it. also you can refer "Windows sample toolkit" which is also available on store.
Answer to your question : you can check menu flyouts control from XAML control gallery. you will also get code there

ContentControl.Content setter always overwrites the content template content

I am fighting with this issue for at least a couple of hours already. I tried all possible solution I found on the net. My latest is below and you will see that I am trying to add a simple MenuBar to the main Window control and present the content beneath. My application is using MVVM and the view is assigned like this:
myMainWindow.Content = view; // this is what I cannot change
The soultion should be trivial but none works. I tried with ContentTemplate, ContentPresenter, Style setter, all the variations with binding but nothing works as expected that is whenever myMainWindow.Content menu bar disappears.
None of the samples available on the internet does not actaully show an application with MenuBar and content at the same time.
Is it so hard to add a menu bar in WPF application?
I would be more than happy for any new suggestions.
Thanks in advance.
<window:BaseWindow x:Class="OneTwoThree.Manager.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:window="clr-namespace:Xsell.Client.Common;assembly=Xsell.Client.Common"
Title="{Binding Title}"
Width="1020"
Height="750"
Closed="AppClosed"
Icon="app.ico"
Loaded="AppLoaded">
<Window.Resources>
<Style TargetType="{x:Type Window}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Grid>
<DockPanel>
<Menu IsMainMenu="True" DockPanel.Dock="Top">
<MenuItem Header="Admin">
<MenuItem Header="Manage Labels"></MenuItem>
</MenuItem>
</Menu>
<ContentPresenter DockPanel.Dock="Bottom"/>
</DockPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
</window:BaseWindow>
Your application isn't really using MVVM. At best it might be sort of halfway using MVVM.
Meanwhile, all the XAML inside your <Window> tag in your main window XAML file is the window's Content. And you are explicitly replacing that with some random object, so of course it's not there any more.
You aren't giving much detail, but you need to assign your main viewmodel to the Window's DataContext and not assign anything to the window's Content.
You didn't say what view is in this line of code, so I have no idea what you were trying to do there:
myMainWindow.Content = view; // this is what I cannot change
Is view a viewmodel, or a view? Whatever it is, don't do that.
You could assign your main viewmodel to the Window's datacontext in XAML, too:
<Window ... >
<Window.DataContext>
<local:MyViewModel />
</Window.DataContext>
<!-- ... -->
</Window>
Then bind your viewmodel to the Content property of a ContentPresenter. There's no need to apply the window's content via a template here so I eliminated that part. The only template you need in this snipppet is the DataTemplate which displays your viewmodel in the ContentPresenter.
The layout here is copied verbatim from MainWindow.xaml in a project I recently wrote. I replaced my main menu with yours and omitted my Window.Resources. That's the only change.
<Window ...>
<DockPanel>
<Menu IsMainMenu="True" DockPanel.Dock="Top">
<MenuItem Header="Admin">
<MenuItem Header="Manage Labels"></MenuItem>
</MenuItem>
</Menu>
<Grid>
<ContentPresenter
Content="{Binding}"
/>
</Grid>
</DockPanel>
</Window>
A simple {Binding} with no Source or Path etc. properties will bind to the DataContext. The ContentPresenter will inherit its DataContext from the Window that contains it.
Then, if you've got a data template defined with a DataType the same as your main viewmodel, that data template will be instantiated in that ContentPresenter.
"Bind" doesn't mean "assign in code-behind". It means to use the System.Windows.Data.Binding class. The easiest way to do that is in the XAML as I've shown above.

VisualBrush (linked to VLC) doesn't change on TabControl selection change

I am having a weird experience with a combination of visual brush (linked to a VLC player through VLC.DotNet) and a tab control. I have created a custom control using the VLC player to watch an RTSP stream and have multiple of these controls in a given window.
The problem is that if I put all the controls in a list view they all display properly. But if I put them in a tab control then it always shows the stream of the first-selected tab item, not matter what tab I'm currently on. Everything else in the control (label, etc.) changes properly, but not the part drawn by the visual brush.
The view for my control is defined as:
<UserControl x:Class="myApp.View.CameraMonitorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Wpf="clr-namespace:Vlc.DotNet.Wpf;assembly=Vlc.DotNet.Wpf"
Loaded="UserControl_Loaded">
<DockPanel>
<Label Content="{Binding Name}" DockPanel.Dock="Bottom"/>
<Grid Margin="3">
<Grid.Background>
<VisualBrush Stretch="Uniform">
<VisualBrush.Visual>
<Image Source="{Binding VideoSource, ElementName=vlcControl}"/>
<!--<Image Source="{Binding Image}" /> -->
</VisualBrush.Visual>
</VisualBrush>
</Grid.Background>
<Wpf:VlcControl x:Name="vlcControl" Margin="3"/>
</Grid>
</DockPanel>
</UserControl>
The code behind for the view starts playing the RTSP, but I don't think that code will help with this problem.
Meanwhile the ViewModel (stripped down for ease of viewing) is just:
class CameraMonitorViewModel : ViewModelBase
{
public CameraMonitorViewModel(string name, string image)
{
Name = name;
Image = image;
}
public string Name {get; set;}
public string Image { get; set; }
}
And I have a data template defined as:
<DataTemplate DataType="{x:Type vm:CameraMonitorViewModel}">
<v:CameraMonitorView HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</DataTemplate>
The full window view model has an ObservableCollection called Monitors and the view displays:
<TabControl ItemsSource="{Binding Monitors}" SelectedIndex="0" Height="300">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Name}"/>
<Setter Property="Content" Value="{Binding}"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
<ListView ItemsSource="{Binding Monitors}" Height="300" />
The ListView properly shows different images from each camera. The tab item will always show the same camera, but the control's label item changes when I clicked different tabs. Moreover, if I replace the databinding to the VLC control's image to the commented out static image object (whose source is set by way of the view model) then the image will properly change when I click different tabs.
I'm really confused and would appreciate any help that could be provided.
Yeah, as I noted in the comment to the question the problem was that I was starting the stream playing based on the Loaded event for the control. But it seems like it doesn't get fired after the second tab, probably because of what Rachel mentions here: Loaded event doesn't fire for the 4th TabControl tab (being that it reuses the template rather than loading multiple ones).

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

How do I "pass through" the inherited properties of Control and ContentControl to an element in a UserControl?

WPF question. I'm not sure what to google for.
I have a usercontrol:
<UserControl x:Class="MyProj.MyControl"
x:Name="Self"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button />
</UserControl>
I use it like this:
<local:MyControl Background="Green" />
But the background doesn't seem to change. It's because the background of the button hasn't changed. I want the background of the button to use the background of the usercontrol.
I suppose I could do this:
<UserControl x:Class="MyProj.MyControl"
x:Name="Self"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button Background="{Binding Path=Background, ElementName=Self" />
</UserControl>
But I pretty much want all of the inherited properties from Control and ContentControl to apply to the button (ToolTip, BorderThickness, BorderBrush, etc).
So what can I do instead of this:
<UserControl x:Class="MyProj.MyControl"
x:Name="Self"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button Background="{Binding Path=Background, ElementName=Self"
ToolTip="{Binding Path=ToolTip, ElementName=Self"
BorderThickness="{Binding Path=BorderThickness, ElementName=Self"
BorderBrush="{Binding Path=BorderBrush, ElementName=Self"
...
...
...
... />
</UserControl>
?
(Note: This is a small (the smallest I could manage, in fact) example of a larger UserControl which hosts many controls.)
Ugh. Well, short answer: You can't, at least not easily. XAML doesn't work quite like HTML/CSS does. The Button (and for that matter, pretty much any Control) does not inherit properties from their containers by default.
You could craft your own Button, etc controls that do inherit...alternatively, you might be able to declare a Style that applies to everything and attempts to grab any containing elements properties (i.e., via RelativeSource FindAncestor)...or you could do what you're doing here: set every property manually.
Example of the Style approach:
<Style TargetType="{x:Type Control}">
<Setter
Property="Background"
Value="{Binding (Control.Background), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Control}}}"/>
</Style>

Categories