MenuItem icon returns collection - wpf

When I have a following code, it all works fine:
<Image x:Key="Icons" x:Shared="false"
Source="{Binding Path=Icon}" Height="16px" Width="16px"/>
<Style x:Key="MenuItemStyle" TargetType="MenuItem" >
<Setter Property="MenuItem.ItemsSource" Value="{Binding Children}"/>
<Setter Property="MenuItem.Header" Value="{Binding Text}"/>
<Setter Property="MenuItem.IsEnabled" Value="{Binding IsEnabled}"/>
<Setter Property="MenuItem.Icon" Value="{StaticResource Icons}"/>
</Style>
But I have to load xaml from external source and WPF has a bug that does not allow x:Shared= in that case. So I made Resource dictionary with x:Name=Icons that is compiled internally (Action is database table that has string property Icon and there is path to the Icon):
<Image x:Key="Icons" x:Shared="False"
Source="{Binding Path=Action.Icon}" Height="16px" Width="16px"/>
and the code now looks
<ResourceDictionary x:Key="IkoniceDict" Source="/MVVM_App;component/View/iconimage.xaml"/>
<Style x:Key="MenuItemStyle" TargetType="MenuItem">
<Setter Property="MenuItem.Icon" Value="{Binding Source={StaticResource Icons}}"/>
Problem is that now I get (collection) instead of image:
Need help, please!

You must not specify a key when loading a resource dictionary into the control.
<ResourceDictionary Source="/MVVM_App;component/View/iconimage.xaml"/>
Edit
I guess I'm not clear enough. The above only works if you have nothing but this in that single <SomeControl.Resources> tag.
<SomeControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionary>
<ResourceDictionary Source="/MVVM_App;component/View/iconimage.xaml"/>
</ResourceDictionary.MergedDictionary>
</ResourceDictionary>
<Style x:Key="MyStyleKey" .............>
</Style>
</SomeControl.Resources>
The Resources is a ResourceDictionary type. All entries must have an x:Key. If you assign an x:Key to an ResourceDictionary inside Resources tag, you are putting a dictionary inside dictionary. That is why you need to use ResourceDictionary.MergedDictionary to tell the XAML parser to merge the contents of iconimage.xaml in.

I think that you should set the Path property for your Binding (set it to "Source"):
<Style x:Key="MenuItemStyle" TargetType="MenuItem">
<Setter Property="MenuItem.Icon" Value="{Binding Path=Source, Source={StaticResource Icons}}"/>
When the path is not specified, the default is to bind to the entire object (in your case the collection of icons).
Msdn Binding

Related

Binding styles from ResourceDictionary to usercontrols

I'm new to wpf so I'm looking for a solution and an explanation of why my attempted solution is not working.
Here's my case.
I have several UserControls. In each of them I apply the following style:
<UserControl.Resources>
<Style TargetType="TextBox" BasedOn="{StaticResource Centratura}">
<Setter Property="IsEnabled" Value="{Binding Property1.IsAbilitato}" />
</Style>
</UserControl.Resources>
based on a style defined in a resource dictionary. And it works fine.
But note that for every UserControl, the previous code is identical, except for the binding property, that will be Property1.IsAbilitato, Property2.IsAbilitato, Property3.IsAbilitato...
But this is a code duplication I don't like. I was wondering how to put the style in the resource dictionary and apply the proper binding later in each usercontrol.
I tried using the Tag property like what was suggested here, in this way:
In my user control:
<UserControl x:Class="whatever"
...
Tag="{Binding Property1.IsAbilitato}"
...>
and in the resourcedictionary:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="TextBox">
<Setter Property="IsEnabled" Value="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
</ResourceDictionary>
but it doesn't work. Suggestions? Other solutions? (I'm using MVVM, if it's relevant).
Thanks in advance.
You have to add the Tag to the TextBox itself:
<TextBox Tag="{Binding Property1.IsAbilitato}"/>
if you want the following to work:
<Setter Property="IsEnabled" Value="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" />
But if you want to add it to the UserControl and want all TextBox's to be applied to then you have to change it to:
<Setter Property="IsEnabled" Value="{Binding Path=Tag, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" />

WPF XAML - Adding multiple styles to resource dictionary which target rowdefinition

Thanks for your thoughts in helping a relative beginner understand WPF.
I am trying to use the following style template in an XAML file for a WPF application:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<Style TargetType="{x:Type RowDefinition}"
x:Key="hideIfNotDischarged">
<Style.Triggers>
<DataTrigger Binding="{Binding DischargedBy28Days,
Mode=OneWay}" Value="false">
<Setter Property="Height" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type RowDefinition}"
x:Key="hideIfOutcomeKnownAndAlive">
<Style.Triggers>
<DataTrigger Binding="{Binding IsKnownDead,
Mode=OneWay}" Value="false">
<Setter Property="Height" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
Which will be later used in a grid like so:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="30" />
<RowDefinition Style="{StaticResource hideIfNotDischarged}" />
...
However, if there is more than 1 style element targeting Type RowDefinition AND ALSO the ResourceDictionary is nested within a MergedDictionary (even with only a single child ResourceDictionary to merge) the application fails with
System.Windows.ResourceDictionary.DeferrableContent: Item has already been added.
That is, despite the fact the 2 styles have different keys, the resource dictionary is trying to add a dictionary item with name based purely on the target type (and ignoring the key).
Any help with how I might overcome this would be most appreciated.
Xaml is parsed left to right so I think its checking the ResourceDictionary or the other MergedDictionaries if the TargetType (default identifier if no x:Key is used) exists before it realizes it has an x:Key identifier
Try setting the x:Key before the TargetType.
this could be a bug in the Xaml parser or it could be by design, It may be worth a look on Microsoft Connect

How to set a ResourceDictionary to a ContentControl.Content?

In my application, I have a ContentControl and this shows the Content property using DataTemplates.
Right now, I need to pass this DictionaryResource to the content property. So I did this (I'm not sure)
<ContentControl Content="{Binding CurrentViewModel">
<ContentControl.Resources>
<ResourceDictionary Source="/MathematicsBusiness.Infrastructure;component/Resources/ThemeResources.xaml" />
</ContentControl.Resources>
</ContentControl>
And this contain my dictionary:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="40" />
<Setter Property="FontFamily" Value="Georgia" />
</Style>
<!--<Style x:Key="TextBlockStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="40" />
<Setter Property="FontFamily" Value="Georgia" />
</Style>-->
</ResourceDictionary>
And it works, all the data templates show the textblocks with that style. But if I use the commented style, it does not work. It throws me an error:
Cannot find a Resource with the Name/Key TextBlockStyle
Why is happening that? If the style does not have a Key, it works. But if I set a key, it doesn't work.
If you specify a key without using it, it should not be a problem. My guess is that you are calling TextBlockStyle somewhere else (maybe your visual state or your code).
The error you are having usually happens if you are trying to use the key, but you haven't specified it in your xaml.
Other possible cause is that you are trying to use the key outisde the ContentControl.

How to define all textblock elements the same color

We are using global styles definitions for most of the types. We define then in the app.xaml file. When using TextBlock it is a problem to define a foreground color because it changes all the controls using TextBlock (Button's content color for example).
How can we define a global style which will act only on specific TextBlock usages?
current problematic usage:
<Style TargetType={x:Type TextBlock}>
<Setter Property="Foreground" Value="Red"/>
</Style>
Since I don't think there is a way to differentiate “your” TextBlocks and those that are part of other controls, your options are quite limited.
You could create named Style and add Style="{StaticResource coloredTextBlock}" or Foreground="{StaticResource textBlockColor}" to all TextBlocks. This would be quite tedious and non-DRY.
You could create your own type that inherits from TextBlock and style that. This has some of the disadvantages of the above solution (you have to remember doing that). But it has much less repetition.
This is because ContentPresenter creates a TextBlock for a string content, and since that TextBlock isn't in the visual tree, it will lookup to Application level resource. And if you define a style for TextBlock at Application level, then it will be applied to these TextBlock within ControlControls.
A workaround is to define a DataTemplate for System.String, where we can explicitly use a default TextBlock to display the content. You can place that DataTemplate in the same dictionary you define the TextBlock style so that this DataTemplate will be applied to whatever ContentPresenter effected by your style.
Add this to your Application resources and it should work for you -
<DataTemplate DataType="{x:Type system:String}">
<TextBlock Text="{Binding}">
<TextBlock.Resources>
<Style TargetType="{x:Type TextBlock}"/>
</TextBlock.Resources>
</TextBlock>
</DataTemplate>
Declare a namespace in your xaml, if not referred already -
xmlns:system="clr-namespace:System;assembly=mscorlib"
EDIT : Check this sample where its working..
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Red"/>
</Style>
<DataTemplate DataType="{x:Type system:String}">
<TextBlock Text="{Binding}">
<TextBlock.Resources>
<Style TargetType="{x:Type TextBlock}"/>
</TextBlock.Resources>
</TextBlock>
</DataTemplate>
<Style TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="Yellow"/>
</Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Foreground" Value="Blue"/>
</Style>
Just provide a x:key in the style, like:
<Style x:Key="stRedTextBlock" TargetType={x:Type TextBlock}>
<Setter Property="Foreground" Value="Red"/>
</Style>
and mention the key in the TextBlock control style, where ever you require this particular TextBlock style, like:
<TextBlock Name="textBlock1" Style="{StaticResource stRedTextBlock}" />

Setting an Elements.Resource Style using BasedOn within a Resource Dictionary

I have a Resource Dictionary that I am using to define the look-and-feel (style) for my application.
I have just created another Resource Dictionary that contains DataTemplates that I am using on several different screens (and even multiple times within the same screen) to display my business objects.
I would like to change some of the default styles within my DataTemplates so that the controls fit better; however I would like the controls to inherit the same style as the rest of the screen. So, naturally I want to use the BasedOn property for this task.
The problem that I am having is that I'm not sure what to set the BasedOn property to.
For example, in the resource dictionary that contains my styles (called "myStyle.xaml") I have:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:primatives="clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type Label}">
<Setter Property="Foreground" Value="#F5F5F5" />
<Setter Property="FontSize" Value="12"></Setter>
<Setter Property="Width" Value="120"></Setter>
<Setter Property="FontFamily" Value="Arial"></Setter>
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="FontSize" Value="12"></Setter>
<Setter Property="Width" Value="120"></Setter>
<Setter Property="Height" Value="25"></Setter>
<Setter Property="Background" Value="Black"></Setter>
</Style>
<!-- .... and so on .... -->
</ResourceDictionary>
I am using this resource in the following window:
<Window x:Class="SiteSetupWindow4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:primatives="clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework"
Title="A Screen">
<Window.Resources>
<ResourceDictionary x:Key="defaultStyleX">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary x:Name="DefaultStyles" Source="Resources/myStyle.xaml" />
<ResourceDictionary x:Name="Templates" Source="Resources/myTemplates.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
Now, I have another Resource Dictionary that contains DataTemplates that I am using within my window. It is called "myTemplates". The style is applied to the DataTemplate as expected; however, I would like to overwrite some aspects of the style within the DataTemplate (Like width for example).
This is what I have tired, however I cannot get the BasedOn property to work...
(myTemplate.xaml)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DataTemplate x:Key="PanelInfo">
<StackPanel>
<StackPanel.Resources>
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Width" Value="120" />
</Style>
<Style TargetType="Label">
<Setter Property="Width" Value="180" />
</Style>
<Style TargetType="ComboBox">
<Setter Property="Width" Value="120" />
</Style>
<StackPanel.Resources>
<StackPanel Orientation="Horizontal">
<Label Content="Type:"></Label>
<ComboBox>
<ComboBoxItem Content="{Binding Path=Type}" IsSelected="True"></ComboBoxItem>
</ComboBox>
<!--...and so on -->
</StackPanel>
</StackPanel>
</ResourceDictionary>
This fails....I have also tried using DynamicResource, but this also fails.
I'm not sure how to get around this.
Any advise would be greatly appreciated!
Thanks,
-Frinny
I was having the same problem with an extended Button Style.
The ResourceKey= is what solved it for me.
This worked:
<Style x:Name="ButtonVisibility"
TargetType="{x:Type Button}"
BasedOn="{StaticResource ResourceKey={x:Type Button}}">
The way you have BasedOn for a type is correct. This will work in theory as long as, at run time, the style that you are basing it on is merged into the tree correctly. Make sure you have the "myStyles.xaml" merged in correctly. You can check this by removing your style you tried to modify and make sure it displays correctly from your style in "myStyles.xaml."
If it isn't there are a lot of places you can go wrong, but it always helps to try merging the styles in the file you are working on, then work up the tree to see where it's missing.
This utility will help you look at what is happing in the tree at run time.
http://blois.us/Snoop/

Resources