I'm am adding the following code to the constructor of App.xaml.cs in my WP7 application.
Resources["PhoneBackgroundBrush"] = new ImageBrush
{
ImageSource = new BitmapImage(new Uri("/images/bg.png", UriKind.Relative))
};
after running it I get NotImplementedException once the applicaion is opened.
Any idea of how can we do this?
What I'm trying to achieve is a single theme application like Facebook that always have white theme regardless of phone's theme.
As a note, getter on the resources always work, so it's not that accessing phone resources is totally blocked from code. (I'm using this to determine current theme and accent of phone).
var a = Resources["PhoneBackgroundBrush"]; // this works fine
For simple examples it isn't complicated when you know how, however you shouldn't rename PhoneBackgroundBrush, but create a new key for your resources.
You need to create the resources in App.xaml (or you can pull in MergedDictionaries other places too, but that's more advanced). Test.jpg needs to be a resource file in your project.
In App.xaml:
<Application.Resources>
<ImageBrush x:Key="MyImageBrush" ImageSource="Test.jpg"/>
</Application.Resources>
In a page for example:
Background="{StaticResource MyImageBrush}"
If you're starting to re-template a control (say a Button), that when you need to crack open Blend and modify the default styles of controls. It's pretty well documented, and builds on these same principles...
Basically the reason you're getting a NotImplementedException is because the setter for the Application.Resources is implemented like this:
set
{
throw new NotImplementedException();
}
The reason Facebook is all white, is because they defined their own colour resources, and used them everywhere. I've also made a always-white themed app. It just requires a little extra effort.
Related
I'm epxloring different ways to best show dialog windows in my application.
MahApp Metro's IDialogCoordinator seems quite useful, but I couldn't quite adjust it to my use case yet.
Say I'm creating a UserControl (view), whose ViewModel needs to be able to display dialogues.
These dialogues should, when displayed, overlay/span the UserControl only, NOT the entire Window in which the UserControl is hosted.
Is there any way to achieve this?
Default behavior always seems to span over the entire window, and I haven't found any way to change this yet.
So far, I've been using the Dialog coordinator in a very straightforward way, doing the following in my view:
<UserControl
xmlns:Dialog="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"
Dialog:DialogParticipation.Register="{Binding}">
and set set the instance in my view's constructor by,
viewModel.Initialize(DialogCoordinator.Instance);
which I'd then call in the viewmodel via
IDialogCoordinator _DialogCoordinator; // set with viewModel.Initialize() called from the view
private async Task _SomeCmdExecute()
{
await _DialogCoordinator.ShowMessageAsync(this, "HEADER", "TEST");
}
Thanks!
Dialogs in MahApps.Metro are always at the window level (see the container PART_MetroActiveDialogContainer in the window's style.)
What you can do is changing the styling of dialogs, so they don't stretch horizontally accross the entire window. See the default template MetroDialogTemplate for reference.
I'm working on an application, and I'm using the MVVM approach.
Basically, there are currently two Pages, and 1 MainWindow.
I switch between the pages using a Frame inside MainWindow.
In the main window, there are 2 buttons which are basically global and should show in all pages; x (exit) and settings.
This is basically my 'shell', as I decided to not use a window border.
The problem is I'd like each page to have a different background and this is where it gets complicated:
- Settings page: Grey background.
- Main Page: Rotating background color that changes according to a property.
The thing is the background is being set in the main window, because it should apply to the global area as well (the top, where the exit and settings buttons are).
I first set the background (in MainWindow) as bound to a property the represents the current page (the value is then being translated into a color hex code with the help of a converter).
All in all, this results in a case where the background changes when a page is changed, but not when the property inside MainPage changes. I can clearly understand why, but I have no idea how to solve it.
The possible solutions I came up with so far:
Somehow causing the binding in MainWindow to update/refresh when the property is changed in MainPage.
Changing the background manually from inside each of the pages. (Although doesn't it negate the idea of mvvm?)
Move the background into each of the pages and set it from there, while making the global buttons on top of the page (which could be a bad thing in case controls end up overlapping).
If so, what would be the best solution to this problem?
If you haven't already, I'd suggest you install some package via NuGet to make MVVM style development more enjoyable. I personally prefer MVVMLight which is... well, light, but it also packs lot's of helpful features.
To communicate between ViewModels, you have (at least) two possible approaches.
1) ViewModelLocator (not recommended)
ViewModelLocator is central place holding references to all of your viewmodels. You could add a property that is then used by all of the viewmodels to get/set the background.
....
x:Name="Main"
DataContext="{Binding Source={StaticResource Locator}, Path=MainVM}">
....
<Grid Background="{Binding Background, Converter={StaticResource StringBrushConverter}}">
...
2) Messenger (recommended)
When ever property changes in your viewmodel(s) or method is executed, you could send a message that your MainViewModel is registered to listen to. Sending a message would be as easy as...
Messenger.Default.Send(new UpdateBackgroundMessage(new SolidColorBrush(Colors.Blue)));
And you'd register for this message in your MainViewModel's constructor:
Messenger.Default.Register<UpdateBackgroundMessage>(this, message =>
{
Background = message.Brush;
});
Actual message class would be:
public class UpdateBackgroundMessage : MessageBase
{
public UpdateBackgroundMessage(Brush brush)
{
Brush = brush;
}
public Brush Brush { get; set; }
}
I know I'm simplifying things here but I hope you got the idea. Both approaches are valid even if you decide not to use MVVMLight.
Edit:
Here's Git repo with example https://github.com/mikkoviitala/cross-viewmodel-communication
I think you should use Application Properties for storing background. There are various benefit of this :
1) Globally available
2) Easy to remember or store user preference
3) Automatically maintain separate profile for each user as it store values in AppData folder of user.
you can use Messenger to notify that background property has changed so that main window or shell could pull out new background value and update it.
I'm currently getting to grips with WPF resources and wondering if you can help me:
I have a WPF window which contains its own resources. It also contains a content control which changes its content depending on what is selected in a tree view, e.g.:
contentControl1.Content = someUserControl;
This can be a UserControl e.g. SomeUserControl which uses a static resource which I have defined in the window xaml.
When creating an instance of SomeUserControl in the window code behind, I get an XMLParseException ('Provide value on 'System.Windows.StaticResourceExtension' threw an exception.'). This is on the line containing the binding to the static resource.
To solve this, I added this to the constructor of SomeUserControl (parentResources being the window's resources from where someUserControl is instantiated):
public SomeUserControl(ResourceDictionary parentResources)
{
this.Resources.MergedDictionaries.Add(parentResources);
InitializeComponent();
}
Is this the best approach for finding resources in this particular case? Thanks for any help.
I assume you have a {StaticResource myResource}. Have you tried using {DynamicResource myResource}?
See http://msdn.microsoft.com/en-us/library/ms748942.aspx
EDIT
Ok, given that you're resource is a converter, which cannot use a dynamic resource, then I think what you're doing is probably as a good a solution as any.
The underlying issue is that at the moment that your control is instantiated, it is not a part of the Window and so it doesn't have any access to the Window's resources. And as the term static in StaticResource implies, the control expects that the resource is going to be available. So you have to make it available when the control is instantiated.
You might also want to look at something like Prism and it's Region's which might be a better way to handle swapping out your "controls" (depending on your needs).
It depends on what resource you're talking about, actually.
Cause the way you do it could be pretty fine, with only drawback, that you detach yourself from declarative programming, which is expected way of coding in WPF.
You can also add a StaticResource, for example in App.xaml, so it will be initialized and loaded as soon as your app starts, and in any way, before window load.
Hope this helps.
I'm trying to set the current WPF Application ResourceDictionary programatically. (I have a WindForms project, so no "App.xaml" to do that for me).
Note: If anyone knows how to bind the equivalent of an Application.Resources to a ElementHost and all of its child controls hierarchy, this is the ultimate objective here.
I added to my code:
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("/Middlewerks;component/Resources.xaml", UriKind.RelativeOrAbsolute) });
Now it works perfectly in the application, the styling is fine (i.e.: Grids' backgrounds are red. It's just a test style).
But if I open this form in the designer, Visual Studio goes crazy. The whole window uses my style!
Here's a screenshot: http://localhostr.com/files/8368cc/Failure.jpg
The cool part is that I found how to edit the Visual Studio 2010 ugly blue skin. The sad part is that won't make my customers happy when they develop with my control.
Feel free to try it and tell me how I should implement my resources without screwing everything up.
XAML Code: (shown in screenshot)
EDIT: Here is my temporary, very hackish solution so I can keep on developing. It really is a pain that "Application.Current" works on Visual Studio.
if (Application.Current.MainWindow == null || !Application.Current.MainWindow.Title.EndsWith(" - Microsoft Visual C# 2010 Express"))
{
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("/Middlewerks;component/Resources.xaml", UriKind.RelativeOrAbsolute) });
}
When I worked on a WinForms project that used WPF areas, I just used MergedDictionaries to bring in the resources I needed, whenever I needed them.
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="DefaultResourceDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
Can you get away with that? You can still put a code behind on the dictionary if you need to do more programmatically.
You can use this at any level on any element. That is, it doesn't have to be a Window as shown here.
I have a set of styles and brushes defined in a ResourceDictionary that I am loading as a MergedDictionary in XAML of my top-level control:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyAssembly;component/Styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
I am trying to optionally replace some of these styles & brushes if a different XAML file exists in the XAP with its own ResourceDictionary. I am trying to merge in this dictionary at runtime before InitializeComponent() is called on my user control. I am using the following code to attempt to do this:
public static class StyleLoader
{
public static void MergeStyle(string xamlUri)
{
try
{
XDocument xaml = XDocument.Load(xamlUri);
ResourceDictionary rd = XamlReader.Load(xaml.ToString()) as ResourceDictionary;
Application.Current.Resources.MergedDictionaries.Add(rd);
}
catch (XmlException ex)
{
// if the file doesn't exist, we can't add it
}
}
}
The resource dictionary from the optional file is loaded fine and merged, however my original set of styles always seems to be overriding this. If I comment out the merged dictionary in XAML and simply load them at runtime in order it works perfectly:
StyleLoader.MergeStyle("/MyAssembly;component/Styles.xaml");
StyleLoader.MergeStyle("BrushReplacements.xaml");
InitializeComponent();
My problem with this solution is that without the default styles in XAML, I can not open the project in Blend. Anyone have any ideas for a solution that will keep my default styles known to Blend but allow me to optionally override them at runtime with a dynamically loaded resource dictionary? Thanks!
Here is a solution where colors/brushes are applied with bindings instead of referring directly to the static resources:
http://blogs.msdn.com/corrinab/archive/2009/11/24/9927729.aspx
Part two:
http://blogs.msdn.com/corrinab/archive/2009/12/02/9931283.aspx
Currently I think something like this is the best way of dealing with dynamically switching themes at runtime. But it does require a lot of work to port an existing application to use a mechanism like this.