Set value in xaml using class field - wpf

I have a DataGrid as:
<DataGrid Grid.Row="4" Name="grvAllCry" Margin="5,5,5,5" ItemsSource="{Binding}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Rank" Width="10*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding Rank}" Foreground="#46BF6E"></Label>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
As you can see, I set Foreground of row of DataGrid is "#46BF6E". But I have many DataGrid and I want to re-use this variables. Something like:
public static class Config
{
public static string MyGreen = "#46BF6E";
public static string MyRed = "#D14836";
public static string MyBlue = "#428BCA";
}
Is there a way I can create a class like that and use it's variable in many different xaml files? For examples:
<Label Content="{Binding Rank}" Foreground="MyGreen"></Label>
I dont know how to call variable from .cs file while in xaml file, pls help me.

You could create a new ResourceDictionary where you define a Brush resource:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="myBrush" Color="#46BF6E"/>
</ResourceDictionary>
If you want to be able to reference this resource throughout your entire application, you can then merge this resource dictionary into your App.xaml:
<Application x:Class="WpfApp1.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>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
...and reference the resource from any view using the StaticResource markup extension:
<Label Content="{Binding Rank}" Foreground="{StaticResource myBrush}"></Label>

it is possible to referense static property or field (including const fields) using {x:Static ...} extension. For Config class it should be:
<Label Content="{Binding Rank}" Foreground="{x:Static myNameSpace:Config.MyGreen}"/>
xaml file should include namespace definition of Config class (xmlsns:myNameSpace="....")
However, reusable elements are usually defined as Resources. Resources which are visible across the application are defined in App.xaml:
<Application.Resources>
<SolidColorBrush x:Key="MyGreen" Color="#46BF6E"/>
<SolidColorBrush x:Key="MyRed" Color="#D14836"/>
<SolidColorBrush x:Key="MyBlue" Color="#428BCA"/>
</Application.Resources>
such resources can be used from StaticResource/DynamicResource extension:
<Label Content="{Binding Rank}" Foreground="{StaticResource MyGreen}"/>

Related

Sharing DataTemplates between controls

I have a ContentPresenter in a couple of places in my application with exactly the same DataTemplates. For now I simply copy-pasted them, but I'd like to clean that up and share them between ContentPresenter instances. I tried this approach:
<ContentControl Content="{Binding DataEditorViewModel}">
<ContentControl.Resources>
<ResourceDictionary Source="pack://application:,,,/LogAnalyzer;component/PredicateDataEditors.xaml" />
</ContentControl.Resources>
</ContentControl>
Application runs, but DataTemplates aren't being applied, I simply see name of class being ContentPresenter's content instead of defined template. I put templates in ResourceDictionary in the following way:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LogAnalyzer"
xmlns:p="clr-namespace:LogAnalyzer.BusinessLogic.ViewModels.Processing;assembly=LogAnalyzer.BusinessLogic"
xmlns:xwt="http://schemas.xceed.com/wpf/xaml/toolkit">
<DataTemplate DataType="{x:Type p:MessageRuleDataEditorViewModel}" x:Key="{x:Type p:MessageRuleDataEditorViewModel}">
(...)
</DataTemplate>
(...)
</ResourceDictionary>
What should I do to embed DataTemplates correctly in ContentPresenter's resources?
if you define this data template in your app.xaml:
<DataTemplate DataType="{x:Type p:MessageRuleDataEditorViewModel}">
<TextBlock Text="testing" />
</DataTemplate>
and then do something like:
<ListBox ItemsSource="{Binding MyCollectionOfMessageRuleDataEditorViewModels}"/>
then your data template is automatically applied to every object of that same type. dont define a key for your global templates

How to use static resources for automatic DataTemplate resolution in ListView

I have
<ListView ItemsSource="{Binding Path=Fruit}">
<ListView.Resources>
<DataTemplate DataType="Apple">
<TextBlock Text="This is an apple"/>
</DataTemplate>
<DataTemplate DataType="Orange">
<TextBlock Text="This is an orange"/>
</DataTemplate>
<DataTemplate DataType="Potato">
<TextBlock Text="Lets assume potato is a fruit"/>
</DataTemplate>
</ListView.Resources>
where Fruit is
ObservableCollection<IFruit> Fruit = new Observable Collection<IFruit>();
public class Apple:IFruit{ }
public class Orange:IFruit{ }
public class Potato:IFruit{ }
This works fine. But since all of the seperate Fruit markups are quite large, I'd rather move their DataTemplates to their own ResourceDictionaryies in seperate files.
What I am trying to do is
<ListView ItemsSource="{Binding Path=Fruit}">
<ListView.Resources>
<StaticResource ResourceKey="AppleDataTemplate" />
<StaticResource ResourceKey="OrangeDataTemplate" />
<StaticResource ResourceKey="PotatoDataTemplate" />
</ListView.Resources>
where DataTemplates are
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:models="clr-namespace:MyApp.Models">
<DataTemplate x:Key="AppleDataTemplate" DataType="Apple">
<TextBlock Text="This is an apple"/>
</DataTemplate>
</ResourceDictionary>
but this throws
{"'XAML Node Stream: Value of 'System.Windows.Markup.StaticResourceHolder' must follow a StartObject and StartMember.' Line number '130' and line position '18'."}
Where Line number '130' is the <StaticResource> element.
My question then is how does one use static resources for automatic DataTemplate resolution in a ListView?
According to MSDN, shouldn't the StartObject and StartMember be implicit for those elements? Similar to how <Party.Favors> is defined in the documentation?
You could merge those DataTemplate ResourceDictionarys into ListView.Resources by doing:
<ListView ItemsSource="{Binding Path=Fruit}">
<ListView.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="AppleTemplate.xaml" />
<ResourceDictionary Source="OrangeTemplate.xaml" />
<ResourceDictionary Source="PotatoTemplate.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ListView.Resources>
</ListView>
Then, the DataTemplates will be available to ListView. Alternatively, you can merge these ResourceDictionarys at a higher level (i.e. the UserControl XAML file where you have your ListView defined).
You may want to remove x:Key from your DataTemplate definitions in ResourceDictionarys.

How to use style defined in another xaml file inside a style

I had MultiSelComboBoxStyle defined in a xaml resource file, and in another xaml resource file, I have
<Style x:Key="DataGridDemoStyle" TargetType="{x:Type DataGrid}">
....
<ComboBox x:Name="ccBox" Grid.Row="0" Grid.Column="1" Width="9" Height="18" VerticalAlignment="Top" Margin="0" Style="{StaticResource MultiSelComboBoxStyle}" Panel.ZIndex="1"/>
....
</Style>
I put every xaml in App.xaml and the compiler did find this MultiSelComboBoxStyle style , but debugging the program says MultiSelComboBoxStyle was not found. In App.xaml
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="DataGridCustomizations.xaml" />
<ResourceDictionary Source="MultiSelComboBoxStyle.xaml"></ResourceDictionary>
It turns out I need to do
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MultiSelComboBoxStyle.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
If needs to use styles from different resource files.

How to Define Common Resources Across WPF Applications (including templates)?

I am looking for a way to define a WPF resource (for now, to be used as a static resource) that is accessible from everywhere within my application.
My resource is defined in this resource dictionary:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="flatButtonStyle" BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" TargetType="{x:Type Button}">
<Setter Property="BorderThickness" Value="4"/>
</Style>
</ResourceDictionary>
The selected answer to this question indicates that I must merge that resource dictionary into my App.xaml file (of a project called AppWideResources):
<Application x:Class="AppWideResources.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/AppWideResources;component/CommonResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
At first, this seems to work; the button in this window is appropriately styled in a flat way with an extra-thick border:
<Window x:Class="AppWideResources.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="AppWideResources" Height="300" Width="300"
>
<StackPanel>
<Button Style="{StaticResource flatButtonStyle}" Content="Test" HorizontalAlignment="Stretch"/>
</StackPanel>
</Window>
However, this stops working as soon as I use my shared resource in a control template:
My (extremely simplified, for the purpose of this question) control:
using System;
using System.Windows;
using System.Windows.Controls;
namespace AppWideResources
{
public class MyControl : Control
{
static MyControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), new FrameworkPropertyMetadata(typeof(MyControl)));
}
}
}
... and the corresponding Themes\Generic.xaml file:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AppWideResources">
<Style TargetType="local:MyControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyControl">
<StackPanel Orientation="Horizontal">
<Button Style="{StaticResource flatButtonStyle}" Content="1"/>
<Button Style="{StaticResource flatButtonStyle}" Content="2"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
This control is then inserted into my window:
<Window x:Class="AppWideResources.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AppWideResources"
Title="AppWideResources" Height="300" Width="300"
>
<StackPanel>
<Button Style="{StaticResource flatButtonStyle}" Content="Test" HorizontalAlignment="Stretch"/>
<local:MyControl/>
</StackPanel>
</Window>
If I run this, a XamlParseException is thrown, saying that the static resource flatButtonStyle cannot be found.
The only workaround I have found is by explicitly merging the common resource dictionary into the local resource dictionary of the control template:
<ControlTemplate TargetType="local:MyControl">
<ControlTemplate.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/AppWideResources;component/CommonResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ControlTemplate.Resources>
<StackPanel Orientation="Horizontal">
<Button Style="{StaticResource flatButtonStyle}" Content="1"/>
<Button Style="{StaticResource flatButtonStyle}" Content="2"/>
</StackPanel>
</ControlTemplate>
However, not only is this quite verbose and error-prone with several lines of redundant code (my actual project contains quite a few templated controls, not just one), I am also concerned about wasting system resources by loading the static resources several times (once for every time CommonResources.xaml is included). (Is that concern justified? Or does WPF use the same instances every time when loading a particular resource dictionary?)
So, the question is: What is the proper way to make a WPF resource accessible throughout the whole application, including control templates?
StaticResource will be resolved and assigned to the property during the loading of the XAML which occurs before the application is actually run. So, static resource has to be available at the time of loading.
It works for normal button since resource look up continues till application resources and resolve it from there. But MyControl template still not loaded into app visual tree so it can't traverse upto application resources.
There are two ways to achieve that:
Merge ResourceDictionary in Generic.xaml as well which you have already achieved.
Other way is to use DynamicResource which assigns an Expression object to the property during loading but does not actually lookup the resource until runtime when the Expression object is asked for the value. This defers looking up the resource until it is needed at runtime.
Read it here - StaticResource v/s DynamicResource.
This will work without merging dictionaries in Generic.xaml:
<Button Style="{DynamicResource flatButtonStyle}" Content="1"/>
<Button Style="{DynamicResource flatButtonStyle}" Content="2"/>

WPF Global Resources in App.xaml

I have created a custom Treeview control and am trying to access the HierarchicalDataTemplate resource of this control from another page in the same project.
my this.sceneTemplate property is coming up null. I have looped through all the objects in the dictionary and it does exist.
How can I access this template?
Thanks
App.xaml
<Application x:Class="Foo.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
DispatcherUnhandledException="App_DispatcherUnhandledException">
<Application.Resources>
<ResourceDictionary>
<!--Merge the global resource to the application-->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Global.xaml"/>
<ResourceDictionary Source="Resources/Scrollbar.xaml"/>
<ResourceDictionary Source="/Controls/TreeView/Themes/Generic.xaml"/>
<ResourceDictionary Source="/Controls/ListButton/Themes/Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Where I am trying to access the resource from my Scene.xaml.cs page
public LeagueDataTemplateSelector()
{
if (Application.Current != null)
{
this.sceneTemplate = (HierarchicalDataTemplate)Application.Current.FindResource("Scene");
this.ItemTemplate = (HierarchicalDataTemplate)Application.Current.FindResource("Procedure");
this.sub1Template = (HierarchicalDataTemplate)Application.Current.FindResource("SubProc1");
this.sub2Template = (HierarchicalDataTemplate)Application.Current.FindResource("SubProc2");
}
}
Scene HierarchicalDataTemplate
<HierarchicalDataTemplate x:Key="Scene" ItemsSource="{Binding XPath=Level}"
ItemContainerStyle="{StaticResource RadTreeViewItemStyleSub1}"
ItemTemplate="{StaticResource Procedure}"
>
<Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label VerticalContentAlignment="Center"
BorderThickness="0"
BorderBrush="Transparent"
Foreground="{StaticResource ListItemUnHighlight}"
FontSize="24"
Tag="{Binding XPath=#name}"
MinHeight="55"
Cursor="Hand"
FontFamily="Arial"
KeyboardNavigation.TabNavigation="None"
Name="SubItem" >
<Label.ContextMenu>
<ContextMenu Name="editMenu">
<MenuItem Header="Edit"/>
</ContextMenu>
</Label.ContextMenu>
<TextBlock Text="{Binding XPath=#name}" VerticalAlignment="Center" TextWrapping="Wrap"></TextBlock>
</Label>
</Grid>
</Border>
</HierarchicalDataTemplate>
Update - Answer
Our program has a breadcrumb control that works by using a list of pages to navigate through. This list of pages was getting added during the splash screen before InitializeComponent was being ran. I moved this up above the page list code and everything in App.xaml is now found.
Our program has a breadcrumb control that works by using a list of pages to navigate through. This list of pages was getting added during the splash screen before InitializeComponent was being ran. I moved this up above the page list code and everything in App.xaml is now found.

Resources