I have a program wrriten in WPF (C#) where all of the elements has a style that points a static resource located in a ResourceDictionary by the name "Styles.xaml";
Since I need to have the styles customed, I use this file to change colors and fonts to elements all across the program.
The problem is, In order to see the changes I need to recompile, and to have another EXE wich is a slight differ version of the program (differ by colors).
I don't want to maintain many versions of the program.
Is it possible to have a ResourceDictionary (or any other file) outside of the compiled EXE to function as css does with HTML?
Meaning, is it possible to achieve the following: replacing the file in the folder where the EXE lies will be sufficient in order to change the colors?
Thank you.
You can obtain a ResourceDictionary instance from .xaml file (not necessary included in your project) by calling XamlReader.Load method and casting the resulting object afterwards. From that point it comes down to manipulating this dictionary in code behind. On application level you can call something like
Application.Current.Resources.MergedDictionaries.Clear();
Application.Current.Resources.MergedDictionaries.Add(dictionary);
where dictionary is the instance you have loaded. The same can be done for individual controls.
Thanks to Nikita Brizhak , I have succeeded.
Here is the full "HOW TO":
1) You need to add an OnStartUp method to App.xaml.cs. Here is the syntax:
protected override void OnStartup(StartupEventArgs e)
2) You have to clear all the resources.
Application.Current.Resources.Clear();//This is if you have on your App.xaml a load of your resource. Clear it and than load another.
//It is good to have this so you can see you style while working on the project, But on runtime to replace.
Application.Current.Resources.MergedDictionaries.Clear();
3) you Have to load your dynamic resource
Final Code:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Application.Current.Resources.Clear();
Application.Current.Resources.MergedDictionaries.Clear();
StreamReader stream = new StreamReader("Styles.xaml");
Application.Current.Resources.MergedDictionaries.Add(System.Windows.Markup.XamlReader.Load(stream.BaseStream) as ResourceDictionary);
}
Related
I basically copied code from here and then changed variables to mine. I have also copied the files under the folder ExpressionBuilder.
And inside the ShyHeader.cs, there is such line of code:
var scrollViewer = gridView.GetFirstDescendantOfType<ScrollViewer>();
So I tried same thing for my ListView but it says undefined:
SongsListView.GetFirstDescendantOfType<ScrollViewer>()
So I put a ScrollViewer around the SongsListView and use that. But I fail to get it working for my project. The header is neither sticky above nor shy. It just gets scrolled normally. Can anyone help me debug it?
SongsListView is here.
SongsListView is used here in HeaderedPlaylistControl.
ShyHeader is implement here at the bottom.
HeaderPlaylistControl is used in AlbumPage, MyFavoritesPage and PlaylistsPage.
So I tried same thing for my ListView but it says undefined
This is extension method for DependencyObject. You could find it here and copy it to you project.
So I put a ScrollViewer around the SongsListView and use that. But I fail to get it working for my project.
I checked your code, you need call SetShyHeadermet method when
PlaylistInfoGrid loaded.
private void PlaylistInfoGrid_Loaded(object sender, RoutedEventArgs e)
{
SetShyHeader();
}
How do I create a resource that I can reference and use in various parts of my program easily?
My specific problem is that I have a NotifyIcon that I want to change the icon of depending on the state of the program. A common problem, but one I've been struggling with for a long time.
Well, after searching around and cobbling together various points from around StackOverflow (gee, I love this place already), most of the problems were already past this stage. I did manage to work out an answer to my problem though.
How to create a resource:
In my case, I want to create an icon. It's a similar process, no matter what type of data you want to add as a resource though.
Right click the project you want to add a resource to. Do this in the Solution Explorer. Select the "Properties" option from the list.
Click the "Resources" tab.
The first button along the top of the bar will let you select the type of resource you want to add. It should start on string. We want to add an icon, so click on it and select "Icons" from the list of options.
Next, move to the second button, "Add Resource". You can either add a new resource, or if you already have an icon already made, you can add that too. Follow the prompts for whichever option you choose.
At this point, you can double click the newly added resource to edit it. Note, resources also show up in the Solution Explorer, and double clicking there is just as effective.
How to use a resource:
Great, so we have our new resource and we're itching to have those lovely changing icons... How do we do that? Well, lucky us, C# makes this exceedingly easy.
There is a static class called Properties.Resources that gives you access to all your resources, so my code ended up being as simple as:
paused = !paused;
if (paused)
notifyIcon.Icon = Properties.Resources.RedIcon;
else
notifyIcon.Icon = Properties.Resources.GreenIcon;
Done! Finished! Everything is simple when you know how, isn't it?
The above didn't actually work for me as I had expected with Visual Studio 2010. It wouldn't let me access Properties.Resources, said it was inaccessible due to permission issues. I ultimately had to change the Persistence settings in the properties of the resource and then I found how to access it via the Resources.Designer.cs file, where it had an automatic getter that let me access the icon, via MyNamespace.Properties.Resources.NameFromAddingTheResource. That returns an object of type Icon, ready to just use.
The above method works well.
Another method (I am assuming web here) is to create your page. Add controls to the page. Then while in design mode go to: Tools > Generate Local Resource. A resource file will automatically appear in the solution with all the controls in the page mapped in the resource file.
To create resources for other languages, append the 4 character language to the end of the file name, before the extension (Account.aspx.en-US.resx, Account.aspx.es-ES.resx...etc).
To retrieve specific entries in the code-behind, simply call this method: GetLocalResourceObject([resource entry key/name]).
Code posted by Matthew Scharley has a memory leak:
paused = !paused;
if (paused)
notifyIcon.Icon = Properties.Resources.RedIcon;
else
notifyIcon.Icon = Properties.Resources.GreenIcon;
You should Dispose() notifyIcon.Icon before replacing it, because Properties.Resources.SOME_ICON creates a new Icon each time it is used.
This can be observed in the log, with this code:
Console.WriteLine(Properties.Resources.RedIcon.GetHashCode());
Console.WriteLine(Properties.Resources.RedIcon.GetHashCode());
Console.WriteLine(Properties.Resources.RedIcon.GetHashCode());
You will see 3 different Hash Codes in the log. This means these are different Objects.
So, the simple fix will be:
paused = !paused;
notifyIcon.Icon?.Dispose();
notifyIcon.Icon = paused
? Properties.Resources.RedIcon;
: Properties.Resources.GreenIcon;
I have a WPF application without an application.xaml, since I need to do the Main() method by myself. Therefore I neither have an ApplicationDefinition nor an application resource. I currently attach the resource dictionary to the application at the application startup
Of course the WPF Designer complains now about missing resources.
So I want to get rid of two problems:
- I don't want to attach the resource dictionary manually at startup
- I want to get the resources also work at design time in the WPF designer
Is there any help for this problem?
Thanks
Martin
There is a possibility to use the Main() method for yourself
Just delete the following property from the xamlcode of Application.xaml:
StartupUri="MainWindow.xaml"
Then add the following in the code-behind of the Application.xaml:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
// My code goes here, but nothing ever happens.
base.OnStartup(e);
}
}
Now you can still use the Application.xaml for your resources and also have your specific startup procedure.
I wrote a bunch of code in the .cs file in c# for a winforms application. The application runs fine, and everything is in it's place.
Something like this:
using..
namespace Temp
{
public class Temp : Form
{
Button b1;
TextBox t1;
Temp()
{
b1.Text = "Some Text";
b1.Size = new Size(50,20);
...
}
void function1()
{
// stuff
}
static void Main()
{
Application.Run(new Temp());
}
}
}
How can I modify my code (or fix it somehow) so that the design view displays the elements in their correct positions and view so that I can visually edit them instead of having to trial/error everything.
Edit for Clarification
My application runs fine. The problem is, that I didn't use designer to create the application and so in the designer view, the app is empty. But not empty when I run it, since everything is positioned programmatically in the .cs file. My question is, how can I fix this, so that the designer shows the objects correctly.
There is no quick fix other than to redesign everything?
So to get this shown within the designer you have to know how the designer works.
For every MyForm.cs there will automatically be a file called MyForm.Designer.cs be created. Within this Designer file there will be only one function called InitializeComponents(). This function will be called within the constructor of your MyForm.cs file.
The design viewer itself is responsible for the Designer file, so any change to this file while the design view is open would normally be discarded. Also if you put some code into the designer file that is not needed be the designer will be truncated.
So the next question is, when will this truncation happen? When you freshly open the design viewer of a form, it will read in everything from the Designer.cs file without making any changes. If you make any changes onto the form by the designer the complete file will be rewritten with all the settings already read in including your latest changes.
This behaviour can be monitored if you open the designer file also as source code view, make some little changes in design mode and afterwards take a close look at the left of the source file. There will be the changes marked with a yellow or a green marker.
Now after all this stuff of informations, you can try the following procedure to get your code into the designer:
Open the design view and put some simple control onto your form (e.g. TextBox)
Save and close the design view and open the Designer.cs file as source file
Copy all your variables name of your controls at the end of the file, right below the textBox1 line
Copy all your control property settings within the InitializeComponent() function right below the property settings of the TextBox
Copy all your control constructors to the top of the file, right below the constructor of the TextBox
Save the file and open your form in design view
Select the dummy TextBox on the design view and delete it
This change within the DesignView leads to a complete rewrite of the designer.cs file, ordering all your manually added stuff the right way.
So this is the way to go. Last but not least another little trick:
Every programmer uses the using-statement to not write the whole path to every class (like System.Windows.Forms.TextBox), but the designer writes always the whole path. To make it a little easier for your copy and paste session you can also add a using statement at the top of the file. After saving and changing something in Design View all this stuff will be re-written automatically. So you don't need to add all this paths manually while your adding your stuff to the Designer.cs file.
Your best option is probably to use the properties panel in the designer to set the positions etc (or maybe just drag them?).
You could go digging around in the designer file for the form (something.Designer.cs), but this isn't a fantastic idea because it can be pretty sensitive to changing things in ways the designer doesn't expect. Having said that, it looks like you're not actually using the designer to make your form (the class would be partial, for one thing), in which case you're SOL.
In that case, you need to copy the designer code from CS to designer.cs. So that you can use designer. I think this is the simplest approach.
Looks like this file was hacked from a class file instead of being generated by the system when you create a new winform.
You need at least an InitializeComponent(); call in your constructor. However you are missing a lot of other code that is generated for you when you create the file such as Dispose().
Best bet would be to right click your project in the solution explorer and click Add Windows Form then start over.
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.