Why don't MenuItems work with DynamicResource? - c#

The main menu of my program uses a ContextMenu composed of MenuItems. During the localization of my program (using Resource Dictionaries), I set a DynamicResource as the Header of each one of my MenuItems. Strangely DynamicResource compiles, but doesn't seem to affect any change during localization (the language on the Headers does not change).
Example of a MenuItem:
//I'm not sure if the x:Name or the PlacementRectangle is interfering with anything...
<ContextMenu x:Name="MainContextMenu" PlacementRectangle="{Binding RelativeSource={RelativeSource Self}}">
<MenuItem Header="{DynamicResource open}" />
</ContextMenu>
What are the constraints of the MenuItem control? Is it supposed to work with DynamicResource? My overall goal is to localize these strings, how do I do that?
This program is in WPF. Thank you.
UPDATE:
This is how my Resource Dictionaries are referenced in my App.xaml file:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Lang.en-US.xaml" />
</ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<Application.Resources>
UPDATE 2:
The example string in my English Resource Dictionary:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String x:Key="open">Open</sys:String>
</ResourceDictionary>
Update 3:
An example function for how I change the current Resource Dictionary to Spanish:
private void spanishChange_Click(object sender, RoutedEventArgs e)
{
Application.Current.Resources.MergedDictionaries.Clear();
Application.Current.Resources.MergedDictionaries.Add(
(ResourceDictionary)Application.LoadComponent(new Uri("LangspES.xaml", UriKind.Relative)));
LanguageChange.FireLanguageChanged();
}

Have you added LANGUAGE.xaml file to App.ResourceDictionary or control ResourceDictionary?
e.g.
<Application.Resources>
<ResourceDictionary Source="LANGUAGE1.xaml" />
<ResourceDictionary Source="LANGUAGE2.xaml" />
</Application.Resources>
If not how are you referencing your resource dictionaries?
Update:
If you change
<MenuItem Header="{DynamicResource open}" />
to
<MenuItem Header="{StaticResource open}" />
Does it then work ? Or even does
<TextBox DockPanel.Dock="Top" Text="{StaticResource open}" />
work ?
Seemingly your xaml should work, which makes me wonder have you setup localisation correctly in your app?
For how to setup localisation in .net 4.5 see this msdn link

Related

How to reference BindingProxy instance from ResourceDictionary

Sooner or later any wpf programmer begin to use BindingProxy.
I am trying to split xaml by moving some of resources into separate resource dictionary. My problem is that resources contain reference to BindingProxy.
How can I handle this situation?
As an example, lets say there is a resource with BindingProxy which is used somewhere
<Window.Resources>
<local:BindingProxy x:Key="proxy" />
<ControlTemplate x:Key="test">
<TextBlock Text="{Binding DataContext.Test, Source={StaticResource proxy}}" />
</ControlTemplate>
</Window.Resources>
<Control Template="{StaticResource test}" />
and code behind
public partial class MainWindow : Window
{
public string Test { get; set; } = "Test 123";
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
}
It may not be the best example, using BindingProxy is not really justified, but it serve demonstration purpose well. During run-time window with text "Test 123" will be shown.
Now lets try move resource to resource dictionary Dictionary1.xaml
<ResourceDictionary ... >
<ControlTemplate x:Key="test">
<TextBlock Text="{Binding Test, Source={StaticResource proxy}}" /> <!-- error here -->
</ControlTemplate>
</ResourceDictionary>
and change main window resource to
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
<local:BindingProxy x:Key="proxy" />
</ResourceDictionary>
</Window.Resources>
<Control Template="{StaticResource test}" />
will lead to desinger and run-time exception
System.Windows.Markup.XamlParseException: ''Provide value on 'System.Windows.Markup.StaticResourceHolder' threw an exception.' Line number '5' and line position '20'.'
Inner Exception
Exception: Cannot find resource named 'proxy'. Resource names are case sensitive.
How can I reference proxy? Is there another technique exist to reference somethining from resource dictionary? Maybe some kind of RelativeResource approach but for things which are not in visual tree? I can't move proxy into ResourceDictionary1.xaml for obvious reasons: it will not capture DataContext of window.
Even though I don't recommend the BindingProxy in MVVM, this is how I think your problem is resolved:
Bear in mind when you include a ResourceDictionary in your view XAML, it automatically inherits the DataContext of the view hence you can keep the BindingProxy in the ResourceDictionary but you need to specify the binding explicitly.
Remember to also remove the proxy declaration from the View XAML as it is now in the dictionary.
You lose the ability to change the DataContext of the BindingProxy, it will use the DataContext of the consumer view.
ResourceDictionary:
<ResourceDictionary ...>
<!-- NOTE: Data property grabs the DataContext of the consumer view -->
<local:BindingProxy x:Key="proxy" Data="{Binding}" />
<ControlTemplate x:Key="text">
<TextBlock Text="{Binding Data.Test, Source={StaticResource proxy}}" />
</ControlTemplate>
</ResourceDictionary>
Window:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
Snapshot:
Do you really need the BindingProxy?
The suggestion above defeats the purpose of the BindingProxy as it is not needed anymore; note you could just change the ResourceDictionary as follows and it works exactly the same without any need of the BindingProxy:
<ResourceDictionary ...>
<ControlTemplate x:Key="test">
<TextBlock Text="{Binding Test}" />
</ControlTemplate>
</ResourceDictionary>

In WPF, how to reference a StaticResource in App.xaml from merged dictionary

This seems an old question: Why I can not reference StaticResource in App.xaml from a merged dictionary? Here is my code:
App.xaml:
<Application x:Class="WpfResources.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<Color x:Key="MyColor">GreenYellow</Color>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Dictionary1.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="Button.Static.Foreground" Color="{StaticResource MyColor}"/>
<Style TargetType="{x:Type Button}">
<Setter Property="Foreground"
Value="{StaticResource Button.Static.Foreground}"/>
</Style>
</ResourceDictionary>
At design time, everything is fine, I can see the foreground of button is set to MyColor. But at the run time, I got:
Exception: Cannot find resource named 'MyColor'. Resource names are case sensitive.
btw:these code work in UWP, but in WPF, something seems changed. I've done lots search on web and can not find an answer.
Any idea would be appreciated! thx!
(btw: I don't want to change to DynamicResource solution)
Edit:
Why anyone give me a downgrade? any good reason?
Although this is an 'old' question, but based on my search, it still has no proper answer!!
The reason seems to be an order in which xaml parser constructs your Application. First it fills MergedDictionaries. To do that - it needs to construct Dictionary1.xaml, and at this point it fails, because there is no resource with key MyColor yet. To verify this, you can fill resources yourself in the correct order in code:
this.Resources = new ResourceDictionary();
this.Resources.Add("MyColor", Colors.GreenYellow);
this.Resources.MergedDictionaries.Add(new ResourceDictionary() {Source = new Uri("Dictionary1.xaml", UriKind.Relative)});
And now it will work fine.
Of course doing that in code is not an option (just to confirm the source of a problem). As a workaround, you can do this:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<Color x:Key="MyColor">GreenYellow</Color>
</ResourceDictionary>
<ResourceDictionary Source="Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Now xaml parser will first merge your dictionary with resources and then all other dictionaries, so MyColor will be available to all of them.
1. maybe priority of declaration is wrong
It may be useful: can-merged-resource-dictionaries-access-resources-from-app-xaml
2. Another way
i think this is good to define color in a page:
<SolidColorBrush x:Key="MyColor" Color="#fff"/>
then bind buttons foreground to those page color resource:
<Button Foreground="{DynamicResource MyColor}"/>
and in a resource dictionary, binding every Property youe need to that:
<Setter Property="Property" Value="{TemplateBinding Foreground}"/>

Resource Dictionary not working - Exception raised for Name/Key not found

I have just started working with Resource Dictionaries and I am stuck on this because my resource dictionary is not working at all. I have tried code-behind and XAML but every time I get exceptions and the app crashes.
If I reference the Dictionary through XAML I get the exception at runtime that Name/Key is not found. The code I used in App.xaml is:
<Application
x:Class="WatchfreeWebsite.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WatchfreeWebsite.Helpers">
<Application.Resources>
<TransitionCollection x:Key="TransCollection">
<EdgeUIThemeTransition Edge="Right"/>
</TransitionCollection>
<ResourceDictionary x:Key="resourcesDictionary">
<ResourceDictionary.MergedDictionaries>
<local:GlobalTemplates Source="Helpers/GlobalTemplates.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
The resource dictionary holds aDataTemplate and a MediaTransportControlsStyle but I cant seem to reference it through XAML because it gives syntax errors and during the runtime the page produces exception while loading XAML at InitializeComponent(); stage.
Resource Dictionary:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WatchfreeWebsite.Helpers"
x:Class="WatchfreeWebsite.Helpers.GlobalTemplatesClass"
xmlns:data="using:WatchfreeWebsite.Helpers">
<DataTemplate x:Key="StreamBoxItemTemplate"
x:DataType="data:StreamingHelper">
<TextBlock Text="{x:Bind StreamName, Mode=OneWay}"
Style="{StaticResource BodyTextBlockStyle}"
TextWrapping="NoWrap"
MaxLines="1"
TextTrimming="WordEllipsis"/>
</DataTemplate>
<Style TargetType="MediaTransportControls"
x:Key="myCustomTransportControls">
<Setter Property="IsTabStop" Value="False" />
.......
</Style>
</ResourceDictionary>
The class behind the resource dictionary is:
public partial class GlobalTemplatesClass
{
public GlobalTemplatesClass()
{
this.InitializeComponent();
}
}
I reference the DataTemplate inside the above style and this style is referenced in another page as:
<MediaPlayerElement x:Name="MediaView"
Grid.Row="2"
Source="{Binding MediaSourceObject, Mode=OneWay}"
DoubleTapped="MediaView_DoubleTapped"
AreTransportControlsEnabled="True">
<MediaPlayerElement.TransportControls>
<data:CustomTransportControlsHelper Style="{StaticResource ResourceKey=myCustomTransportControls}"/>
</MediaPlayerElement.TransportControls>
</MediaPlayerElement>
But this is not working and there is a red line below the resource name saying that the resource is not found.
Is there something that I am missing? If someone can help me here please provide your suggestions. Thanks
When you add multiple items under your resources, each of them should fall within the <ResourceDictionary> tag and not directly under <Application.Resources>.
That's because Resources itself is a dictionary, so you're in effect trying to replace that collection rather than add elements to it. Docs here: https://msdn.microsoft.com/en-us/library/system.windows.application.resources%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
I created a sample project with just an App.xaml at the project base level, a folder called Helpers and a ResourceDictionary under Helpers named GlobalTemplates.xaml to match yours.
Created a simple brush as an example in GlobalTemplates.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1.Helpers">
<SolidColorBrush x:Key="DefaultForeground" Color="DarkGreen" />
</ResourceDictionary>
In App.xaml
<Application
x:Class="App1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
RequestedTheme="Light">
<Application.Resources>
<ResourceDictionary>
<TransitionCollection x:Key="TransCollection">
<EdgeUIThemeTransition Edge="Right"/>
</TransitionCollection>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Helpers/GlobalTemplates.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
And then in MainPage.xaml successfully referenced the style from the dictionary:
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Foreground="{StaticResource DefaultForeground}">Hello world</TextBlock>
</Grid>
</Page>

Best way for storing data-string relative to elements

What is the best, most possible, proper way to store data inside elements?
I used to use a separated XML file and now i'm using the Tag and tooltip property.
It's a string-type data, e.g.:
Theme data Theme1.fg.ffffffff;Theme2.fg.ff000000;
Margins according to window size Margin.16:9.10,5,10,5;
With WPF/XAML an ideal approach could be to store such strings in Resources of the respective element or in a ResourceDictionary
eg
<Grid x:Name="myGrid" xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Grid.Resources>
<sys:String x:Key="ThemeData">Theme1.fg.ffffffff;Theme2.fg.ff000000;</sys:String>
<sys:String x:Key="Margins">Margin.16:9.10,5,10,5;</sys:String>
</Grid.Resources>
</Grid>
to use the same you have two approach
xaml approach
<TextBlock Text="{StaticResource ThemeData}" />
code behind
string themeData = myGrid.FindResource("ThemeData");
these resources can also be stored in a ResourceDictionary which can further be merged in any element, window or even whole application
eg
StringResources.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String x:Key="ThemeData">Theme1.fg.ffffffff;Theme2.fg.ff000000;</sys:String>
<sys:String x:Key="Margins">Margin.16:9.10,5,10,5;</sys:String>
</ResourceDictionary>
usage
<Grid x:Name="myGrid">
<Grid.Resources>
<ResourceDictionary Source="StringResources.xaml" />
</Grid.Resources>
<TextBlock Text="{StaticResource ThemeData}" />
</Grid>
or this if you want to merge/override some more resources
<Grid x:Name="myGrid">
<Grid.Resources>
<ResourceDictionary xmlns:sys="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="StringResources.xaml" />
</ResourceDictionary.MergedDictionaries>
<!--define new resource or even override existing for this specific element -->
<sys:String x:Key="ThemeData">Theme1.fg.ff00ff00;Theme2.fg.ff0000ff;</sys:String>
<sys:String x:Key="NewMargins">Margin.16:9.10,5,10,5;</sys:String>
</ResourceDictionary>
</Grid.Resources>
<TextBlock Text="{StaticResource ThemeData}" />
</Grid>
The way I understood, you can use Tag property on controls to store the info . it accepts object type. hence you can attach any type to it. like control.Tag = objectyouwantto attach.
if my answer seems not relevant, please elaborate your question

How to apply the same theme in all WPF windows using MahApps.Metro

I'm newer with WPF projects and I have a question about the component MahApps.Metro.
I created a MainWindow and other windows in my project, my question is: How to apply the same theme in MainWindow to the others windows of the project? And, I must to apply the ResourceDictionary for all windows or exist any way to do this one time only?
Thank you guys!
In your App.xaml, set the ResourceDictionary property like this:
<Application.Resources>
<ResourceDictionary Source="MyResourceDictionary.xaml"/>
</Application.Resources>
Notice that in order for the styles in your resource dictionary to be applied to all controls of that type, the style should NOT have a key. For example, a style defined like this:
<Style TargetType="{x:Type Button}">
<Setter Property="Content" Value="This is the default button text"/>
</Style>
In the ResourceDictionary will cause all the buttons in the project to have a default value when you create them.
Resource's in WPF work based on their available "scope". Check this article for a detailed explanation
Now Application(App.xaml) is in a higher scope to Window. Thus to share these MahApps control resources across your Window's just move the ResourceDictionary's to the Application.Resources scope
something like:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colours.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Now you no longer need to add these Dictionary's in each Window as they are available implicitly

Categories

Resources