Silverlight 4 - Setting design time style of User Controls in controls project? - c#

I have a few user controls that need to be shared between multiple Silverlight 4 project. I am creating a new project that defines those controls in a namespace called [appname].[UI]
I want to create a new Stylesheet for all these controls within the project, however I don't know how to reference the styles at design time (I can reference them via the style="" attribute, but they never get applied).
More over I do know that the application has to "Register" the style sheet as part of its resources. Is there a way to do so from within my UI project?
Am I wrong with my assumptions or is there any work around these issues?

To register, add the <MergedDictionary> tag in your App.xaml <ResourceDictionary> entry. This will allow the application to access your styles, like so:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="YourResourceFile.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Once they are registered, the Style="" attribute should work, but if it doesn't, post the code. It might be an error in the XAML.

The silverlight terminology surrounding styles is a bit confusing. It sounds like when you say stylesheet that you really mean templates. If you want to consistently set public properties on controls (eg. FontSize, Background, etc), you'll want to use a style. But if you want to change the way the control is laid out you're going to want to set a new control template. Modifying the control template is much more powerful for customizing controls but also can be a pain because as far as I know you can only edit templates via the XAML. I think you might be able edit the templates WYSIWYG if you're using Expression Blend.
Overview of differences between Styles and Templates:
http://msdn.microsoft.com/en-us/library/cc295273.aspx

Related

wpf Access to 3rd party Themes and Skins via ResourceDictionary

I'm creating a WPF Revit Addin. For this I'd like to use some 3rd party controls for extra UI functionality and for their styles (see ModernWpf])
Within a 'normal' WPF application it all works fine: I add the library (nuget) and added the themes resouces to the app.xaml's ResourceDictionary.MergedDictionaries.
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ThemeResources />
<ui:XamlControlsResources />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Adding (for example) a DropDownButton control to a page and running the WPF app results in a working and styled DropDownButton.
DropDownButton with styling
In my Revit Addin this doesn't work somehow. Since there is no app.xaml, I tried to add the resources at different places (Window, Page, UserControl, my theme resource MainTheme.xaml, ... The control itself is shown and the dropdown action works, but there is no styling.
DropDownButton without styling
The ModernWpf.dll and ModernWpf.Controls.dll are copied to the Revit Addins folder, and these dll's hold the resources (as seen with DotPeek), so these should be available somehow.
DotPeek on ModernWpf.dll
What am I missing / how can I fix this?
Thanks in advance, Michel
As you pointed out, in Revit add in there is no app.xaml so no assembly wide resources either, this is because Revit add in is a class library, not a proper WPF application. You can check out this question and take one of the approaches. In my add-ins, I fixed this issue like this:
Create xaml file with resource dictionary, for example "Resources.xaml" (to easily create WPF things inside class library, check out this question)
Create your global resources in "Resources.xaml"
Create this class. Replace *name of your project* with name of your project.
public class SingletonResources : ResourceDictionary
{
private static ResourceDictionary? inst;
public SingletonResources()
{
if (inst is null)
{
var uri = new Uri("/*name of your project*;component/Themes/Resources.xaml", UriKind.Relative);
inst = (ResourceDictionary)System.Windows.Application.LoadComponent(uri);
}
MergedDictionaries.Add(inst);
}
}
Then in every control where you want to be able to access "Resources.xaml", inside of control resources include SingletonResources. Like this:
<Window.Resources>
<revitPluginUi:SingletonResources>
</revitPluginUi:SingletonResources>
</Window.Resources>
Now you can access all resources from "Resource.xaml" inside window.
IDE autocompletion for resource keys will not work.
Important note: if you need to create local resources for control, and you defined SingletonResources you need to define local resources inside SingletonResources tag. Like this:
<Window.Resources>
<revitPluginUi:SingletonResources>
<SolidColorBrush x:Key="MyLocalBrush"/>
</revitPluginUi:SingletonResources>
</Window.Resources>

How does WPF allow named items to be recognized across the entire application?

When a named XAML element is used in a WPF application, it can be accessed from anywhere. For example:
<Grid>
<Grid>
<TreeViewItem Name="itemScreen" />
The element itemScreen will be directly accessible in MainWindow(), although it is several levels deep in the XAML hierarchy.
How does WPF enable this to work in C#?
There's a mechanism called NameScope.
https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/wpf-xaml-namescopes
Simple markup you put in a window which has no templating or styling will all have the one namescope.
If you dig through that link it will explain about styles and templates in more detail. Essentially, they have their own namescope.
This is probably as far as you want to go with an explanation at this stage but there are a couple of oddities like when you "inherit" a style using basedon.
I wouldn't worry about them just yet but throw it to the back of your mind for later.
ps
That control is a private member of your window and the name doesn't have to be unique across the entire application.

WPF Styling from External Libraries and Static Resources

I'm writing several C# controls in a library that will be accessed throughout an entire application. My structure looks like this:
Solution
-App 1
-App 2
-App 3
-Control Library (with WPF Control's)
Everything works mostly well -- but the thing is that I also have some resources in my code that are trying to be accessed from that Control Library.
The Control Library has a StyleLoader, which will execute the following (and is executed prior to loading each App):
public static void IncludeVisualStyles(Control control)
{
control.Resources.MergedDictionaries.Add(
new ResourceDictionary
{
Source = new Uri("pack://application:,,,/my.app.UI;component/Styles/generic.xaml",
UriKind.RelativeOrAbsolute)
});
}
Each app calls this StyleLoader.IncludeVisualStyles(x) on it's root Window.
Now, if my Window/View's use an item in this library, i.e. MyAppColor, it cannot find it, if I were to use the following line (in App1):
<TextBlock>
<TextBlock.Foreground>
<SolidColorBrush Color="{StaticResource MyAppColor}">
</TextBlock.Foreground>
</TextBlock>
It will throw a XamlParseException, claiming it cannot find the MyAppColor. If I manually link in the Resource at the top of the UserControl in App1 (not the Window) with the XAML equivalent of the StyleLoader.IncludeVisualStyles (creating a Merged Dictionary in the UserControl.Resources) it works fine. But I don't want to have to do this manually, and instead, to link the resources with code.
I'm contemplating going the route of creating a static styling library and just using x:Static Library.MyAppColor, but this seems like a workaround that might confuse other WPF developers.
Any thoughts on how to fix this or what might be happening? Any further consideration with how resources and styles work would be immensely appreciated.
EDIT: Might I also add that if I make the StaticResource's DynamicResource's, they SOMETIMES work. For example, if I have ControlA and ControlB, ControlA will not receive the styling/color correctly, while ControlB will -- and this is on base controls for WPF, like a Border, TextBlock, CheckBox, etc.
EDIT 2: The application's are not "true" applications -- they contain a logical bootstrapper that creates Windows. They exist as plugins to VSTO's, which has no concept of an application. My thoughts were to link in the resources to the Window, and hope that when searching for the resource, it would search up the tree to THAT merged dictionary, but no such luck.
Now I'm not sure what exactly your project structure looks like, but the following works for me:
Create a WPF Control Library project, add a Resource Dictionary:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="testBrush" Color="Red"></SolidColorBrush>
</ResourceDictionary>
Create a WPF application, add a Startup event to App.xaml with the following code (pretty much what you did):
private void Application_Startup(object sender, StartupEventArgs e)
{
Resources.MergedDictionaries.Add(
new ResourceDictionary()
{
Source = new Uri("pack://application:,,,/WpfControlLibrary1;component/Dictionary1.xaml")
});
}
Reference the resource in my Window:
<Window x:Class="WpfApplication1.MainWindow"
...
Background="{StaticResource testBrush}">
With Styles, it works the same.
If you want to add your resources later that this, you need to use DynamicResource instead. My guess is that you're calling your IncludeVisualStyles method too late. What exactly does it mean "prior to loading each app"? If you're doing it in Application_Startup, like I did, the Window is not created yet, unless you're creating it manually.
Of course, as HighCore remarked, unless you really have a good reason to not do it, just link it in App.xaml's Application.Resources.

ResourceDictionary organization in WPF style library

We have a WPF library that contains styles that are used in many of our products. It is organized as follows. Each indented level is merged into the library above
WpfResources.xaml
Color.xaml
ButtonStyle.xaml
Color.xaml
OtherStyle.xaml
Color.xaml
SliderStyle.xaml
Color.xaml
The problem with this approach is that as you can see Color.xaml is added to each and every control style I add. This might and I'm not sure give a performance hit. All colors brushes, margins etc in Color.xaml are frozen though.
If I remove Color.xaml from the control ResourceDictionaries the visual studio designer will start complaining about missing StaticResources for colors and other things declared in Color.xaml. I could replace them by DynamicResources but that is not wise performance wise.
Any ideas on a better organization of styles?
In our application, we have a ResourceDictionary only for colors. So every color in our app is loaded in this files. Then we have our Styles and Templates XAML files for all controls, not separated ones like you put it.
One thing I've learned is, if you're repeating something, it could be better. Here's our App.xaml file just for an example. Keep in mind that with one Color.xaml you can make a lot of Themes/Skins!
When someone asks for a a new style, it only takes about 10 minutes to get it done! Here it is:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Cmp.Wpf;component/CmpEstilos/Colors.xaml" /> <!-- Our Colors are here! -->
<ResourceDictionary Source="pack://application:,,,/Cmp.Wpf;component/CmpEstilos/Styles.xaml" /> <!-- Our Styles are here! -->
<ResourceDictionary Source="pack://application:,,,/Cmp.Wpf;component/CmpTemplates/Templates.xaml" /> <!-- Our Templates are here! -->
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
This code is inside App.xaml - just to remind you.
Nothing against your approach but I think that it would be easier to maintain if you have one file responsible for each "responsibility".
Good luck.

Is there any way to use StaticResource in a WPF control library and be able to view at design-time?

I have a WPF Control Library that is being added to a windows forms application. We want to allow the controls to be localizable, however I am not sure how to FULLY accomplish this without duplicating code. This is what I am doing now.
Basically, in the windows forms app, before the main application kicks off, I am instantiating an App.xaml that live within the forms app (containing my links to my resources that also live within the forms app). This works perfectly for runtime.
However, my user controls all have Content="{StaticResource SomeVariableName}", which end up being blank. I can fix this by having an app.xaml and appropriate resource dictionaries in my control library that match those in my windows forms app. However, this is duplicated code.
Things I have already tried to no avail:
Instantiate the App.xaml that lives within the user control library from within my forms app. This does not work because the URIs to my resources is looking for an embedded resource, not my local resource dictionary (I could then simply copy the resource files from the control to an appropriate location within my forms app on build). Could I leverage DeferrableContent here? There is not much online as far as I could find on this attribute and how it should be used, though.
I would like to use post builds for both App and dictionaries, however, the App instantiation is a static reference to a compiled App.xaml as far as I can tell. So, App.xaml must live within the form at least
I did try to have a duplicated App.xaml with a post build moving the resourcedictionary.xaml. I figured that a duplicated app.xaml is ok since that is the driving force and you might not want to rely on one from the control anyway (which circles back and makes you wonder if you should then have the App.xaml in the control at all? Unless you want to allow a default that uses embedded resources....) That too failed saying it could not find the resource even though it was placed where the URI should have been pointing to. The decompiled code points to Uri resourceLocater = new Uri("/WindowsFormsApplication3;component/app.xaml", UriKind.Relative);
So, Is there any way to allow for this to work AND have design time viewing of the component defaults AND avoid duplication? Or, is the duplication OK in this case? If my 2nd bullet's sub-item seems ok (duplicated App.xaml with build copied resourcedictionaries), how do I make it not look for a component level item, but instead a file level one?
Last question (and I can post this separately if necessary) that I just paid attention to. My App.xaml is being built into the code, so that does not allow me to create new ResourceDictionaries on the fly anyway. Is there any way to do this?
Final option...possibly the best one?
- I plan on using Andre van Heerwaarde's code anyway, so should I just check for the existence of a file and add it as a merged resource on the fly? Basically, have one App.xaml in my user control that links to a default embedded ResourceDictionary. And, then have the code look for the appropriate localized resources on the fly, which can be relative file paths? The only downside I see here is that the default cannot be changed on the fly...which I could probably even have that look in a specified place (using some sort of convention) and have that preferred over the built-in one?
Oh, and my reason for not wanting embedded resources is so that end users can add/modify new localized resources after the build is deployed.
I can add code if it will help you visualize this better, just let me know.
UPDATE
I am now running into a further problem with styling and not just localizing.
Here is an example of one of the internal buttons on one of the controls:
<Button Style="{StaticResource GrayButton}"
Some more things I tried/thought:
I cannot create an app.xaml (that would never be used) with the ResourceDictionary set up as ApplicationDefinitions are not allowed in library projects. I could embed this in the control's resources, but then that would always take precedence over any application level resources and I lose customizability.
Here is a connect case that actually sounds like what I am looking for, however it does not provide any real solution to this
The solution (beyond the top..which does not work) that I can think of that might work (and have yet to try) also seems like a lot of work for something that I would think should be simple. But, I might be able to create some dependency properties in the control that I can Bind to and then allow those to be overriden by the project that will be using the control. As I said, that seems like a lot of work for a pretty simple request :). Would this even work? And more importantly, is there a better, simpler solution that I am missing?
I've run into this problem once, and I resolved it by dropping the whole "Resources are objects indexed by key in canonical dictionaries" thing.
I mean, the simple fact of defining a resource in one project and referencing it in another by it's "key" should give goosebumps to any sane person. I wanted strong references.
My solution to this problem was to create a custom tool that converts my resource xaml files to static classes with a property for each resource:
So MyResources.xaml:
<ResourceDictionary>
<SolidColorBrush x:Key="LightBrush" ... />
<SolidColorBrush x:Key="DarkBrush" ... />
</ResourceDictionary>
Becomes MyResources.xaml.cs
public static class MyResources {
static MyResources() {
// load the xaml file and assign values to static properties
}
public static SolidColorBrush LightBrush { get; set; }
public static SolidColorBrush DarkBrush { get; set; }
}
For referencing a resource, you can use the x:Static instead of StaticResource:
<Border
Fill="{x:Static MyResources.LightBrush}"
BorderBrush="{x:Static MyResources.DarkBrush}"
... />
Now you got strong references, autocompletion and compile time check of resources.
I too had a problem dealing with Styling Themes and available static resources. So, I created a stand-alone library that basically had nothing but the themes to be used all nested like your MERGED resources of your prior linked question.
Then, in the Windows form (.xaml), I just put reference to that library, something like
<Window x:Class="MyAppNamespace.MyView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" ... />
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- Common base theme -->
<ResourceDictionary Source="pack://application:,,,/MyLibrary;component/Themes/MyMainThemeWrapper.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Rest of XAML for the WPF window>
</Window>
The "component" appears to refer to the root of the given "MyLibrary" project. In the actual project, I created a subfolder called "Themes", hence the source includes... ;component/Themes/...
The "MyMainThemeWrapper.xaml" is very much like your nested Merged Resource dictionaries, and it sees everything perfectly from other libraries.
Here's my partial solution to your problem. I haven't tried to handle loose resources, but I have some success with sharing resources between WinForms and WPF.
Create a class library to contain your resources in .ResX files (e.g. Resources.resx, Resources.fr.resx, etc)
Create your WPF controls in a WPF user control library
Create your WinForms host
Reference the resources in your resource library from WPF using the Infralution.Localization.Wpf markup extension and culture manager, e.g.
<TextBlock Text="{Resx ResxName=ResourceLib.Resources, Key=Test}"/>
Put the content of your WPF user controls into one or more resource dictionaries as control templates,e,g
<ControlTemplate x:Key="TestTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="{Resx ResxName=ResourceLib.Resources, Key=Test}"/>
</Grid>
</ControlTemplate>
Use the resource template in your user controls
<UserControl x:Class="WpfControls.UserControl1"
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" mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" >
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<ContentControl Template="{StaticResource TestTemplate}" />
</UserControl>
Add a couple of lines of code to make things work
public partial class UserControl1 : UserControl
{
// we require a reference to the resource library to ensure it's loaded into memory
private Class1 _class1 = new Class1();
public UserControl1()
{
// Use the CultureManager to switch to the current culture
CultureManager.UICulture = Thread.CurrentThread.CurrentCulture;
InitializeComponent();
}
}
Here's a simple demo app called WindowsFormsHost.7z

Categories