Import view from resource file - c#

I have a resources file Grids.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Label x:Key="SomeTestLabel">Hello There</Label>
<Grid x:Key="HomeGrid">
<Label Content="{StaticResource SomeTestLabel}"></Label>
</Grid>
</ResourceDictionary>
And in my Menus.xaml file I have
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TabItem x:Key="HomeTab" Header="Home">
<Grid><!-- PROBLEM IS RIGHT HERE --></Grid>
</TabItem>
</ResourceDictionary>
Is it possible to link <Grid><!-- PROBLEM IS RIGHT HERE --></Grid> with <Grid x:Key="HomeGrid">...</Grid>?
Is there a better View I could use?
Is there a better way to do this?
The main reason I'm doing this is to refactor code out of one file (MainWindow.xaml) and into various other files, so that the main file and main resources file don't get cluttered with random pieces of code

A <ResourceDictionary /> is not ment to be a central place to declare controls. Things that are declared in one of those dictionaries is ment to be used by controls (e.g. styles, brushes, themes, common images, converters and templates).
However, control declarations (e.g. a <Grid />) is always an instance of that particular class that will be rendered by the WPF framework. A control can only exist at one place at a time, therefore, placing one inside a ResourceDictionary is not a good idea (it's not reusable anyway). Control declarations always belong inside the UserControl, Window or other hosting control where you want it to be displayed.

Related

Specify or modify class library style resource values from referencing add-ins

I have a c# wpf-based class library with models, view models, and views, which I am using in multiple add-ins for dektop applications that have APIs which support hosted dockable WPF user controls. From here I can use different controls and launch dialogs to interact with various data structures in the 3rd-party application. My class library doesn't have an App.xaml file.
I have created a ResourceDictionary xaml file that I am using as a main style sheet throughout my views. In my user controls and windows, I reference it:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources/styleMain.xaml"/>
</ResourceDictionary.MergedDictionaries
Inside of this style sheet, I manage my various controls to simplify and unify my views. At the lowest level, I have settings for things like font size, font family, and color. For example, I have several brushes that I use throughout my controls. One looks like this:
<Color x:Key="ColorBase_Primary" R="255" G="0" B="115" A="255"/>
<SolidColorBrush x:Key="Color_Primary" Color="{StaticResource ColorBase_Primary}"/>
This all works great for design and testing. However, I am referencing this class library in multiple other projects. In these other projects, I am hosting the main user control from my class library:
<UserControl x:Class="MyAppHost.ucDockingHost"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyAppHost"
xmlns:viewModels="clr-namespace:MyClassLibrary.ViewModels;assembly=MyClassLibrary"
xmlns:views="clr-namespace:MyClassLibrary.Views;assembly=MyClassLibrary"
mc:Ignorable="d">
<UserControl.DataContext>
<viewModels:vmMain/>
</UserControl.DataContext>
<Grid>
<views:ucMainGrid ViewModelMain="{Binding}" Property1="SomeValue" Property2="SomeOtherValue"/>
</Grid>
</UserControl>
Here I am setting DependencyProperties from the add-in application that references my class library without any problems, and all of my bindings and control behaviors are working great.
What I am now hoping to do is be able to specify from my add-in (and not the main class library) the basic resource values that are used throughout my style sheet, especially color (as in being able to change the value associated with x:Key="ColorBase_Primary"). This way, I can adapt different implementations to the branding of different clients, etc. I have been searching for a long time for any examples or insight and keep coming up short.
It would be easy enough to simply deploy the entire class library independently with each application and adjust the style sheet directly, but that doesn't seem right at all. Is there some way for me to create a ResourceDictionary in my add-in applications that could supply, modify or and/override the resource values specified in my class library? Or should I do it through a DependencyProperty in my view model? That doesn't seem right either.
Do not use the MergedDictionaries in your library, i.e. remove this:
In your application, you then merge all resource dictionaries from your library in the correct order:
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/WpfControlLibrary1;component/Brushes.xaml"/>
<ResourceDictionary Source="pack://application:,,,/WpfControlLibrary1;component/Controls.xaml"/>
</ResourceDictionary.MergedDictionaries>
<SolidColorBrush x:Key="brush">Red</SolidColorBrush>
</ResourceDictionary>
</Application.Resources>
</Application>
You can then simply override any resource you want by defining another resource with the same x:Key like I have done with the SolidColorBrush above. This resource overrides any resource with an x:Key of "brush" defined in either Brushes.xaml or Controls.xaml.

Resources for WPF designer

I have the following structure of objects in my WPF application (simplified):
Main window
<Window>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedResources>
<ResourceDictionary Source="Styles.xaml" />
</ResourceDictionary.MergedResources>
</ResourceDictionary>
</Window.Resources>
<ContentControl>
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:MyViewModel}">
<local:MyEditor />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
...
Then, the editor:
<UserControl>
<!-- No resources here - getting styles from parent -->
...
</UserControl>
Resources in the main window are being managed dynamically (in certain circumstances I clear them and load another set to match theme of application), so I cannot embed the styles in UserControl (otherwise I would have to load styles in that UserControl dynamically as well). Of course apart from fact, that I actually don't even have to embed these styles in user control, because it will get them from parent.
But.
If I don't specify link to resources in XAML, the designer looks very sad (despite complicated structure of the UserControl):
Is there a way to provide information about related resources for the designer only?

WPF Using images in generic.xaml template

I am writing a style for a custom control derived directly from Control. Visual Studio places the style for a "Custom Control (WPF)" in the Themes\generic.xaml file. My style contains an image which I can't get displayed, seems there's something special about how to set the Source for an image from within the generic.xaml file.
I managed to reproduce the issue with a simpler scenario. Create a "WPF Custom Control library" then add a style for buttons like so, in the themes\generic.xaml . Here's my complete generic.xaml:
<ResourceDictionary
...
<Style TargetType="{x:Type Button}">
<Setter Property="Content">
<Setter.Value>
<Image Source="SmallHandle.png"></Image>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
After this I have create a UserControl (in the same project) containing just a button (for the sake of testing out the style) like so:
<UserControl x:Class="BlendControls.UserControl1"
...
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Button/>
</UserControl>
I have added the SmallHandle.png in the root project directory, in the themes directory, I have added it also to the good old Resources page, tried changing the build action to resource, embedded resource, tried copying the image manually to the build directory, but to no effect. The image is never displayed.
This must be related to the generic.xaml file, because copying the entire style to the same file where the Button is placed works fine. That is, the following works as expected:
<UserControl x:Class="BlendControls.UserControl1"
...
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Content">
<Setter.Value>
<Image Source="SmallHandle.png"></Image>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Button></Button>
</UserControl>
So, how should I set the Source of images from generic.xaml? Or alternatively, where should I put the styles/templates for custom controls?
---- Solution ----
As pointed out by Sheridan, I have to use the "full" pack URI notation as:
pack://application,,,/MyAssembly;components/SmallHandle.png
This looks strange to me, as the image is in the same assembly. Not sure, looks like I am referencing from outside the dll.
There's nothing unusual about accessing an image in Generic.xaml, you're just not referencing it correctly. You can reference a resource file in the project assembly using this format:
<Image Source="/AssemblyName;component/Subfolder/SmallHandle.png" />
If your images are directly inside the project root (which is not recommended), then you can access them like this:
<Image Source="/AssemblyName;component/SmallHandle.png" />
If your images are in a folder in another project, then you can access it like this:
<Image Source="/ReferencedAssembly;component/Subfolder/SmallHandle.png" />
See the Pack URIs in WPF page on MSDN for more information.
UPDATE >>>
In .NET 4, the above Image.Source values would work. However, Microsoft made some horrible changes in .NET 4.5 that broke many different things and so in .NET 4.5, you'd need to use the full pack path like this:
<Image Source="pack://application:,,,/AssemblyName;component/Images/image_to_use.png">
If you don't feel as though your generic.xaml is being picked up, you can reference it from your App.cs.xaml like this:
<App.Resources>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MY.NAMESPACE;component/Themes/generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</App.Resources>
Your generic.xaml file should be marked as "Resource".
Also, your image file should be marked as "Resource".
Finally, reference your ImageSource like this:
<Image Source="Themes/IMAGE.png" />
or try
<Image Source="../Themes/IMAGE.png" />
Personally, I like to put my style templates in their own .xaml file, and reference them all as MergedDictionaries.
Typed base style in Themes\Generic style is automatically applied only to Custom Control.
If you need use typed based style in your user control you need add generic.xaml to user control resources.
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Also change Image Source URI to
<Image Source="pack://application:,,,/WpfCustomControlLibrary1;component/SmallHandle.png" />

XAML Inheritance (not code-behind)

How is inheritance accomplished in XAML?
Is it true that only the code-behind can be inherited and not the .xaml (related question)? Is including the parent in the child control's namespace the only way of doing it?
There seems to be no general "inheritance" per se in XAML. There are questions about inheriting UserControl, etc. but not general inheritance.
Problem:
I have 2 xaml files, File1.xaml and File2.xaml, which are very alike. Can I create a SuperFile.xaml and put the bulk of the following code in it?
<UserControl ... >
<Grid>
<Grid.RowDefinitions ... />
<DockPanel ... >
<ToolBar ... >
<!-- Some Buttons here:
File1.xaml to contain the Buttons "View" and "Export"
File2.xaml to contain the Buttons "Edit" and "Delete"
-->
</ToolBar>
</DockPanel>
<igDP:XamDataGrid MouseDoubleClick="xamDataGrid1_MouseDoubleClick" ... />
</Grid>
</UserControl>
The only things that differ in File1.xaml and File2.xaml are:
Buttons in the ToolBar (see comment in the code)
The properties of XamDataGrid, primarily the events (what they do in each case).
How can I achieve this? Would I have to write the code-behind files for both the children separately?
You can use a ResourceDictionary
Put all your generic templates and styles in a ResourceDictionary, then have both your UserControls import that ResourceDictionary
<UserControl.Resources>
<ResourceDictionary Source="BaseStylesAndTemplates.xaml" />
</UserControl.Resources>

wpf image resources and changing image in wpf control at runtime

I would like to know exactly how to dynamically use a Dictionary Resource in the C# code behind - ie.. I would like to load images at runtime from an image resource within a dictionary
I have a program that has 3 images in a WPF Dictionary - these are images set as image resources.
Then in the code behind of my WPF Window I want to load any one of the three images based on user initiated events.
There is no real code I have to show as nothing that I have done works.
Ideas?
First, make sure you've defined your image resources like this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ImageSource x:Key="image1">images/image1.jpg</ImageSource>
<ImageSource x:Key="image2">images/image2.jpg</ImageSource>
</ResourceDictionary>
Secondly, I'm assuming that your WPF dictionary is in its own file. Now you have to make sure you've merged your dictionary into your main window's XAML (skip this step if your resource dictionary is defined inside of the window's XAML). In your window's XAML file, make sure you have something like this:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="myDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
Now, in your code-behind, you can use the FindResource() method to locate your image resource by it's key name (the value of the x:Key attribute on the ImageSource in the resource dictionary) like so:
imageControl.Source = (ImageSource)FindResource("image1");
Hope this helps!
This is an addition to the accepted answer:
When working within a ViewModel from MVVM, make sure to use the FindResource from the view where the resource directory is added.
<Window x:Class="My.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:My.ViewModels"
Title="USA Hockey Player Evaluation tool"
Icon="/USAHockeyPlayerEval;component/View/Images/HET.ico"
SizeToContent="WidthAndHeight"
MinHeight="500px" MinWidth="800px">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Images.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Window.DataContext>
<ViewModels:MainWindowMV/>
</Window.DataContext>
<StackPanel>
<Menu>
<MenuItem Header="File">
<MenuItem Header="Save"></MenuItem>
My view in this case is a window (I know not correct MVVM ;-) )
Image img = new Image();
img.Source = (ImageSource)WindowReference.FindResource("Pluse");
Here the WindowReference is a reference to My.MainWindow.

Categories

Resources