I was going through some code in our product and saw some colleagues using ResourceDictionary.MergedDictionaries in a way I had not seen it used before:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<toolTips:ToolTips />
<styles:ControlStyles />
<icons:IconDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
tooltips:ToolTips and all the other elements in the MergedDictionaries are ResourceDictionaries.
The regular way of using these according to the internet is to use <ResourceDictionary Source="uri to your xaml file"/>.
So is there any practical difference between both?
If this way works why isn't it used more often as it plays well with code completion?
I've used ResourceDicionary this way only once on a big project and it was benefical in my situation.
Suppose that you have ResourceDictionary in MyDictionary.xaml file.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="YourNamespace.MyDictionary">
</ResourceDictionary>
You can add an x:Class attribute to the ResourceDictionary element and specify the fully qualified name of the code-behind class.
Let's create MyDictionary.xaml.cs with class MyDictionary (name can be different from the name of the xaml file).
public partial class MyDictionary
{
public MyDictionary()
{
InitializeComponent();
}
}
A class must be a partial class. The constructor must be added to the class and InitializeComponent method must be called. The InitializeComponent method will be automatically generated for the class if you set the x:Class attribute in MyDictionary.xaml
Now you can reference MyDictionary in MergedDictionaries
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<local:MyDictionary/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
If you add some DataTemplate into MyDictionary.xaml you can create event handlers in code-behind (handlers will be automatically generated by VS)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="YourNamespace.MyDictionary">
<DataTemplate x:Key="MyTemplate">
<Button Click="Button_Click"/>
</DataTemplate>
</ResourceDictionary>
Code-behind:
public partial class MyDictionary
{
public MyDictionary()
{
InitializeComponent();
}
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
// custom logic
// edit another element, etc.
}
}
If the class is inherited from the ResourceDictionary class then other resources can be accessed from the code-behind.
Example of usage of data template defined in MyDictonary:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<local:MyDictionary/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<ContentControl ContentTemplate="{StaticResource MyTemplate}"/>
</Grid>
From my point of view the biggest advantages are that you can encapsulate logic into separated files (it's easy to maintain and add new features in big projects) and avoid referencing ResourceDictionaries by <ResourceDictionary Source="uri to your xaml file"/>.
Related
I have some shared resources that I have bundled within a resource dictionary. The following code works as expected (The resources are loaded at design time and intellisense works perfect.):
Alternative 1:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MyCompany.Helpers.UI;component/Resources/SharedResources.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
At this point I changed the code to:
Alternative 2:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="{x:Static appCode:DesignResource.GlobalResource}"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
public static class DesignResource
{
public static Uri GlobalResource
{
get { return new Uri("pack://application:,,,/MyCompany.Helpers.UI;component/Resources/SharedResources.xaml"); }
}
}
Now Intellisense only gives me: "An error occured while finding the resource dictionary". Am I missing something? Why does Alternative 2 not work?
I am trying to start a MVVM pattern and I have this structure:
App.xaml:
<Application x:Class="StereoVisionApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StereoVisionApp"
StartupUri="MainView.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<local:MainViewModel x:Key="StereoVisionApp.MainViewModel"/>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
MainViewModel.cs:
namespace StereoVisionApp.ViewModels
{
class MainViewModel
{
public MainViewModel()
{
}
}
}
I have an error on this line:
<local:MainViewModel x:Key="StereoVisionApp.MainViewModel"/>
Says:
The name "MainViewModel" does not exist in the namespace
"clr-namespace:StereoVisionApp". StereoVisionApp C:\Users\Me\source\repos\StereoVisionApp\StereoVisionApp\App.xaml
I have tried restarting million times. any help?
In Visual Studio, when you create a new folder in the project at creates a new namespace named projectname.foldername by default. (in your case: StereoVisionApp.ViewModels). All the files inside it automatically takes that namespace.
You can either:
Change the namespace in MainViewModel.cs
or
Add the new namespace to App.xaml like this:
add this in Application header in App.xaml
xmlns:vm="clr-namespace:StereoVisionApp.ViewModels"
Then use it like this:
<vm:MainViewModel x:Key="StereoVisionApp.MainViewModel"/>
Also note that the x:Key value is a string of your choice (doesn't have to be an exact location, so you can actually write:
<vm:MainViewModel x:Key="mainViewModel"/>
The x:Key value is for future reference only.
I've came across this error, which I couldn't find the solution for. I'm implementing an mvvm application and in main window I'm setting the main DataContext in xaml using a loader:
in App.xaml:
<Application.Resources>
<viewModel:KinectViewModelLoader x:Key="KinectViewModelLoader"/>
</Application.Resources>
In MainWindow.xaml:
<Window x:Class="KinectFittingRoom.MainWindow"
...
DataContext="{Binding KinectViewModel, Source={StaticResource KinectViewModelLoader}}">
...
</Window>
Everything was running well, but now I wanted to add some dynamic resources, so I've created some xaml files containing styles and other elements.
In example:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ModelUIElement3D x:Key="BirthdayHatModel">
...
</ModelUIElement3D>
</ResourceDictionary >
To use them in MainWindow.xaml I've added them to App.xaml file as ResourceDirectory and then my application began to crash.
App.xaml:
<Application x:Class="KinectFittingRoom.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:KinectFittingRoom.ViewModel"
StartupUri="MainWindow.xaml">
<Application.Resources>
<viewModel:KinectViewModelLoader x:Key="KinectViewModelLoader"/>
<ResourceDictionary x:Key="ResourceDictionary">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/GlassButton.xaml"/>
<ResourceDictionary Source="Resources/Models/BirthdayHat.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
And now I'm getting an error on App.xaml.cs file saying that KinectFittingRoom.App.OnExit(System.Windows.ExitEventArgs) has no suitable method to override.
My overriden method:
protected override void OnExit(ExitEventArgs e)
{
KinectViewModelLoader.Cleanup();
base.OnExit(e);
}
Mabe someone could explain to me why adding ResourceDirectory node causes my application to throw an error? What can I do to include those resources and avoid such problem? I would appreciate any advice.
I think you need to change two things in your XAML:
In your App.xaml file Move the declaration of your ViewModel inside ResourceDictionary section. Also if possible you should delete x:Key="ResourceDictionary". So now your App.xaml should look like:
<Application x:Class..................>
<Application.Resources>
<ResourceDictionary>
<viewModel:KinectViewModelLoader x:Key="KinectViewModelLoader"/>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/GlassButton.xaml"/>
<ResourceDictionary Source="Resources/Models/BirthdayHat.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
If after following the above step your program does not work then please follow this step along. Change the DataContext Property of your window like the code shown below:
<Window x:Class="KinectFittingRoom.MainWindow"
DataContext="{StaticResource KinectViewModelLoader}">
...
</Window>
If still your application does not work then change the order of the lines in App.OnExit() as follows:
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
KinectViewModelLoader.Cleanup();
}
I have a Window in WPF which simply contains a Frame element. The Frame displays a Page; which Page is displayed changes based on user interaction.
<Window x:Class="MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="720" Width="1280">
<Grid>
<Frame Source="{Binding Source={StaticResource MainPageIntent}, Path=Path}"/>
</Grid>
</Window>
I would like all Pages that appear in that Frame to share a common Resource Dictionary so that they may all be styled in a common way.
Right now I have something like this in every page that this Window loads:
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourceDictionaries/BaseControlStyles/MenuStyle.xaml"/>
I was hoping that I might just be able to set the resource dictionary on the Window, and they would "inherit" those resources, but that does not appear to be the case. I tried something like this, but the styles found in MenuStyle.xaml are not applied the the controls inside the Page loaded by the Frame:
<Window x:Class="MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="720" Width="1280">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourceDictionaries/BaseControlStyles/MenuStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Frame Source="{Binding Source={StaticResource MainPageIntent}, Path=Path}"/>
</Grid>
</Window>
Is there are way to define styles at the Window level such that all pages loaded in child Frames will use those styles?
Note: I do not want to apply these styles to ALL windows in my application, so putting this ResourceDictionary in my App.xaml does not appear to be a valid solution.
If you want to write it once to avoid code duplicates, you can write it in code behind. On frame ContentRendered you can write a code to add resource to the page which is being loaded.
<Frame Name="fr_View" ContentRendered="fr_View_ContentRendered"/>
private void fr_View_ContentRendered(object sender, System.EventArgs e)
{
ResourceDictionary myResourceDictionary = new ResourceDictionary();
myResourceDictionary.Source = new Uri("Dictionary1.xaml", UriKind.Relative);
(fr_View.Content as System.Windows.Controls.Page).Resources.MergedDictionaries.Add(myResourceDictionary);
}
Take a look at this link:
Set up application resources from code
In WPF how do I reference a static resource that is defined in a different XAML file? It's in the same project.
The other XAML file will need to be a resource dictionary. You merge it into the current file using the MergedDictionaries property of the current ResourceDictionary. See Merged Resource Dictionaries on MSDN. Their example:
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="myresourcedictionary.xaml"/>
<ResourceDictionary Source="myresourcedictionary2.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
Then within that Page object you can reference static resources defined in myresourcedictionary.xaml or in myresourcedictionary2.xaml.
"different XAML file" could mean a few different things:
App.xaml: Resources are automatically included in the resource tree of anything that's opened so you don't need to do anything extra.
Window or Page .xaml: Resources can be accessed by any child of an instance of the object like a UserControl that is used in a Window.
ResourceDictionary: Needs to be explicitly merged into the resource tree somewhere above where it is used. This can be App.xaml, Windowxx.xaml, or some lower level element. Use ResourceDictionary.MergedDictionaries to do this.
There are also lots of alternate ways to specify the path but this is the simplest:
<Window>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/MyResourceDict.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>