Apparently I like to complicate my life, but I feel it's worth it.
I have a Solution with more than one WPF projects (each builds into its own application: Server, Client etc.). I'd like to have some settings in one place (mostly labels, so when I change names I won't have to locate it throughout multiple files), so I created project "Common", in it Properties.settings, and in those some positions (ServerName, ClientName).
Now in Server.MainWindow I'd like to set Title property to Common.Properties.Default.ServerName. Of course in XAML. I unfortunately have no idea how to go about it.
Somewhere I found:
<ObjectDataProvider x:Key="odpsettings" ObjectType="{x:Type l:Properties.Settings}"></ObjectDataProvider>
but whatever I type I get
nested properties are not supported
Basically it doesn't work and I don't know where to start...
The problem is that doing something like {x:Static common:Properties.Default.ServerName} is not allowed, but having just {x:Static common:Properties.Default} is OK.
So all you need to do is set the binding source to {x:Static common:Properties.Default} and specify the requested key in the binding path, thus avoiding the whole unsupported nested types issue:
<Window Title="{Binding Source={x:Static common:Properties.Default}, Path=ServerName}">
Related
I have an application for which I use WPF. The application is dependent on a few libraries which I load as embedded resources. Mostly, this works like a charm.
Things go wrong when I try to add my own class library as an embedded resource as well (I'd like to keep the executable standalone). The library still loads and I am able to use all classes and controls it contains. What I am unable to do, however, is to define styles for these controls in any resource dictionary (e.g. app.xaml).
When I try to do something like this:
App.xaml:
<ResourceDictionary x:Class=....
xmlns:library="clr-namespace:myNamespace;assembly=assemblyName">
<Style x:Key="Test" TargetType="{x:Type library:myControl}" />
</ResourceDictionary>
Main.xaml:
<Window x:Class=....
xmlns:library="clr-namespace:myNamespace;assembly=assemblyName">
<library:myControl style="{staticresource Test}" />
</Window>
I get the following error:
InvalidOperationException: 'myControl' TargetType does not match type of element 'myControl'.
Why is this? Can I somehow make clear that in fact, both myControl are the same type?
There are a few things that do work, but arent viable options for me. One is setting the style directly in Main.xaml:
<Window x:Class=....
xmlns:library="clr-namespace:myNamespace;assembly=assemblyName">
<library:myControl>
<library:myControl.Style>
<Style TargetType="{x:Type library:myControl}" />
<library:myControl.Style/>
</library:myControl>
</Window>
which works fine. However, I have hundreds of such controls which all need to implement largely the same style. It wouldn't want to repeat the same style in every window or control including myControl.
Something else that works to my surprise is writing the library data to a file, and then loading it. e.g. if I do:
var assembly = Assembly.GetExecutingAssembly();
string libraryName = "assemblyName.dll";
string library = assembly.GetManifestResourceNames().Where(s => s.EndsWith(libraryName)).First();
using (Stream stream = assembly.GetManifestResourceStream(library))
using (FileStream FS = File.Create(fullPath))
stream.CopyTo(FS);
Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), libraryName));
all my problems are gone. The catch is that now the assembly's loaded and I cannot delete the file I've just created. I've tried bypassing this by loading it into a separate domain and other suggestions given in questions such as this one, but to no avail: I cannot delete the loaded assembly even after unloading the domain it's loaded in.
Upon inspecting the target types of my styles (Style.TargetType) and the types of the controls (control.GetType()) in my wpf window, I found a few differences:
The RuntimeType.Assembly.CodeBase is different when loading the library as an embedded resource: assemblyName.dll for the type of the controls, and application.exe for the TargetType of the styles.
A few pointers also differ between the types: RuntimeType.Assembly.m_assembly and MemberInfo.Module.m_pData. This implies to me that the library is actually loaded twice in differing parts of memory, hence it can't be guaranteed that both types are the same.
This explains why writing the assembly to a file, and then loading it would solve the issue: both types then have Assembly.CodeBase pointing to assemblyName.dll and the pointers also nicely match.
Ultimately I found the following workaround:
By reloading the App.xaml ResourceDictionary in Window.Resources (MainWindow.xaml), the types in the ResourceDictionary are guaranteed to be the same as the type in the controls and everything works accordingly. This causes no issues for me as my application only has a single window, although it does seem a little sloppy to be loading the same ResourceDictionary twice (once application-wide, once in the scope of the window). The real question remains why the assembly codebase is different when loading app.xaml than it is for the rest of the application's lifespan.
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.
Im building an application where I want to head for a design, that could remind of a dockpanel.
What I want, is having buttons in the left side (or left panel) representing different areas of the application (e.g "Milk", "Bread") and then have different "views" in the middle-panel.
What I already have tried, is making an application with a "Frontpage", and buttons changing the whole window/usercontrol - this however will not give me static areas/panels.
I do not want to use a tabcontrol with the tabtitemstrip being vertical - however it is kinda the same functionality im looking to have.
Any ideas?
Below is a picture with the wished design, to kinda give an idea of my thoughts.. Any help appreciated :)
http://s57.photobucket.com/user/RolleKn/media/wpfdesign_zps3737b014.jpg.html
If you use WPF, use ContainerControl or ContentPresenter for that.
In general, "switching Visibility On/Off" is not a good way to go. It forces the UI to create all objects, even those invisible ones, and to handle their data and events, etc.
And you need to switch it all manually.
WPF provides you with many mechanisms that can save you this. Some are smarter than others, some not.
One of the most basic mechanism in WPF is the Control and its Template property. You can replace whole your Grid+Contents+SwitchingVisibility idea with a single Control and switching its Template:
<Window.Resources>
<ControlTemplate x:Key="panel1"> ..carrots.. </ControlTemplate>
<ControlTemplate x:Key="panel2"> ..cucubers.. </ControlTemplate>
<ControlTemplate x:Key="panel3"> ..donkey.. </ControlTemplate>
...
</Window.Resources>
<Grid x:Name="LayoutRoot">
<Control x:Name="foo" />
</Grid>
Now, if you get the foo and set its .Template and set it to panel1, then the "carrots" will show up. if you set it to panel3, donkeys. And so on.
It's very powerful, but it will not be really handy due to some other things I won't cover. There are books and tutorials that explain Templates in depth. Also, this mechanism is really not designed for such task. It's the most basic one, and a good thing to know if you want to work in WPF, but there are more suitable ones here.
Second next powerful and still basic mechanism is ContentControl/ContentPresenter. They work almost in the same way (actually CC uses CP internally), so I'll skip it.
ContentControl is a smart control that knows how to automatically select a correct Template with respect to the data you are tryng to present.
So:
<Window.Resources>
<DataTemplate DataType="CarrotData"> ..carrots.. </..>
<DataTemplate DataType="CucumberData"> ..cucubers.. </..>
<DataTemplate DataType="DonkeyData"> ..donkey.. </..>
...
</Window.Resources>
<Grid x:Name="LayoutRoot">
<ContentControl x:Name="foo" Content="{Binding ..}" />
</Grid>
Note the change from 'ControlTemplate' to 'DataTemplate'.
Now, with this setting, you don't even need to switch templates manually. You just get the "foo" and set its Content to either:
a CarrotData object, that contains the carrot-related data
a CucumberData object, that contains the cucumber-related data
a DonkeyData object, that contains the donkey-related data
Once you set the data to be shown (i.e. foo.Content = carrots[5]), the ContentControl will pick the relevant template to be shown.
You can bind the Content property to just about anything. If you have some dataclass that contains carrots/donkeys and has a property CurrentThing, you can bind to it and ContentControll will switch the views automatically along with the changes to CurrentThing.
That's basics. There's much more to it, in almost any point I tried to briefly cover. For now, leave ControlTemplates. Read about DataTemplates and Bindings. Read about ContentPresenter (shows 1 template for 1 item) and ItemsControl (shows N items+templates). Then, read a little on MVVM pattern.
You will quickly see that "having everything in one Grid" and "switching Visibility" is an odd way to do it.
However, I wouldn't be fair if I didn't mention that everything has a cost included. Extensive use of templates and bindings makes your app a bit slower compared to what you could get when you do everything manually. But usually, doing it manually is just not really worth it.
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
I think I'm asking for a lecture on the proper application of WPF here but I'm going to take my chances since I'm at my wit's end. I think this is probably largely a result of my lethargy in fully embracing WPF templates and styles so I'm happy to listen to any such lectures.
I'm writing a sort of audio editor / event orchestrator. I've got a track editor that I'm fairly happy with. However, I built it largely out of custom controls (I know, this is probably a WPF sin). In keeping with that theme, I want to make a standard header for the tracks but I want the individual track "types" to be able to define what goes in that header. I thought a control that defines a sort of "grip" on the edge and then allowed the implementer to "fill in" the substance would work well. However, I have no idea how to do this in WPF without using styles and even if I end up using styles, I would like to understand this.
This probably comes down to wanting a sort of exemplar implementation of a simple ContentControl control (e.g. a button) and not being able to find one (other than AvalonDock, which ultimately uses - correctly i'm sure - templates for this). In my head, the xaml looks something like this:
<ContentControl x:Class="TestArea.CustomContentControl2"
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">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Hello"/>
<ContentPresenter Grid.Column="1"/>
</Grid>
But of course, that doesn't work. I'm fairly sure I could pull the same thing off by playing tricks with overloads behind the scenes, but it would be nice if I could do something like this. Do I really have to put all my terrible, procedural ways behind me and use these styles you speak of? If so, can someone at least tell me what that button looks like down in the framework?
Here is a complete example of deriving from ContentControl to accomplish what you want: Creating Customized UserControls (Deriving from ContentControl) in WPF 4
Pete's ContentPresenter is doing the same thing as it does in your example.
Using styles allows you to seperate functionality of a control with representation of a control; such as the Button.
Think as a control at the start as nothing more then functionality. A simple class containing predefined events, properties, etc... Once that control takes on the job of becoming part of a visual tree it now needs a visual identity. It didn't need one previously; however now it does. Defining a default style allows that control to now have a visual representation which it did not need prior as it was not living within the visual tree.
Ignoring styles would be like ignoring CSS when making use of HTML.