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;
Related
I am creating a Visual Studio Package (this is my first time) and my end goal is to create a context-menu item for the solution explorer that only works on certain file types. (I thought this would be a common thing, but didn't find any decent tutorials on it, so if you know any please let me know)
I followed a simple MSDN guide to create an item in the toolbar first (I forget where is was to link it) and this worked fine.
Then I found a way to move it to the Solution Explorer context menu. This was achieved by manipulating the .vsct file and having an element like this:
<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_ITEMNODE"/>
That probably doesn't matter, but I am trying to set the scene.
Now, because I want to only show the item for certain file types, I need to find a way to check the file when the right-click button is pressed. Cutting a long search short, I found this and ended up with the following code:
protected override void Initialize()
{
//stuff
OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
menuItem.BeforeQueryStatus += menuItem_BeforeQueryStatus;
//more stuff
}
void menuItem_BeforeQueryStatus(object sender, EventArgs e)
{
var myCommand = sender as OleMenuCommand;
myCommand.Text = "NEW NAME";
}
In the above example I am just trying to set the text to try and prove it works, I know there is a Visible property but I want this step to work first. The BeforeQueryStatus event is fired, and debugging shows the code executing as expected. However, there is no change in the context menu item, it stays with the original text.
What am I missing here? Why is it not updating?
OK, so I have finally found a solution to this problem, there are a couple of things that you need to do...
STEP 1:
We need to specify that the VSPackage should "auto-load", we do this so that the code will execute when the ContextMenu is shown, because normally the VSPackage would not initialise before the UI has been shown (i.e. the menu item has been clicked). To do this we add an attribute to the Package class, like so:
[ProvideAutoLoad("{f1536ef8-92ec-443c-9ed7-fdadf150da82}")]
public sealed class MyFirstPackage : Package
You may wonder what that GUID value is, well in this case it represents the UICONTEXT_SolutionExists constant, which means the the package will auto-load when a solution exists (so when we create a new one or load one). I got this information from here, as you might be able to tell there are a number of different VSConstants that could be used.
Here are a couple more resources that list other GUID values that can be used:
GUID List 1
GUID List 2
STEP 2:
Now that the BeforeQueryStatus code is executing at the correct place, it is still confusing as to why the code doesn't actually change anything (in my question I try to change the Text). Well, the answer is, because we need to give the package permission to do so (at least that's the way I see it as being).
To do this we must edit the .vsct file. Inside there we can find a Buttons element, inside which should be our ContextMenu Button. By default there are some comments which mention the use of the CommandFlag node - this is what we want.
In order to give permission for our package to change the Text we must add the following node:
<CommandFlag>TextChanges</CommandFlag>
Now, if we run the VSPackage it should all work as expected!
If you are looking to allow permission to change the Visibility of the menu item (which was my original aim) then you can use the following CommandFlag:
<CommandFlag>DynamicVisibility</CommandFlag>
There is a full list of command flags here, with descriptions on what they do.
Instead of directly using the guid mentioned in musefan's answer, you can use:
[ProvideAutoLoad(Microsoft.VisualStudio.Shell.Interop.UIContextGuids.SolutionExists)]
Refer to: UIContextGuids Class for all guid constants.
I'm trying to implement the automation test via UIAutomation for our project. But lots of the controls are not standrad, and proper patterns are also not implemented for that controls. How should I to manipulate the controls via UIAutomation framework in this case?
For example, a button in our product is implemented via a Pane, and the invoked pattern is not implemented as well. How should I click the button? (To avoid installing VS on the test machine, I don't want to use Mouse.Click() in Microsoft.VisiualStudio.TestTools.UITesting namespace) Is there a way to do that only using UIAutomation framework or something else embedded in .net framework? Thanks in advance! (If the proper pattern is implemented, Below code will work. And as a new user, I cannot post the screenshot for your reference, sorry!)
object temp = null;
if (btnTest.TryGetCurrentPattern(InvokePattern.Pattern, out temp))
{
InvokePattern btnTestPattern = temp as InvokePattern;
btnTestPattern.Invoke();
}
The only way to interact when Control Patterns are not implemented is to go clicking around stuff.
I would suggest try following to avoid maximum errors.
Before sending the click, make sure the parent of button(pane or window is set to foreground)
Instead of sending the click to corner of the AutomationElement, try sending it in midpoint, of the element,
Also, try hovering over the element first, the wait like 200ms, and then send click, So that you are sure to see execution.[Trust me, this helps debugging a lot and avoids many issues.]
The best thing would be, if those guys who implement the system would implement server-side UIA provider to their UI Elements!
But often that's not possible..., I used the following workaround (at least for clicking/toggling):
AutomationElement yourAE = ...// some code to find the right AutomationElement (AE)
clickablePoint = yourAE.GetClickablePoint();
also BoundingRectangleProperty could be of help
If you receive that clickable point you can use
System.Windows.Forms.Cursor.Position = new System.Drawing.Point((int)clickablePoint.X, (int)clickablePoint.Y);
to move to the location, and than click it via InputSimulator or some win32 (user32.dll) commands.
(note: of course you can also use InputSimulator or win32 to move the mouse - but I had some problems with the InputSimulator when it came to several screens with different locations or resolutions - so Cursor.Position was the easiest approach, which is also very reliable)
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 several checkboxes within ToolStripMenuItem within a window form.
I need to setup the registry (I think this automatic when saving, correct?)
I need to save the checkboxes into registry (during form.closing event)
I need to load the registry and set the checkboxes when form is loaded.
I would like an option to save it to files (save and load) as well.
I read about ConfigurationManager but it look rather complicated (from MSDN source), it this the best solution?. Is there link to simple demo program that done this (to file rather than registry).
Yes, you really ought to use a Setting. Project + Properties, Settings tab. Add one: Name = Option1Checked, Type = bool, Scope = user, Value = false.
In your form's Load event, you'd write:
option1ToolStripMenuItem.Checked = Properties.Settings.Default.Option1Checked;
And in the FormClosing event, you'd write:
Properties.Settings.Default.Option1Checked = option1ToolStripMenuItem.Checked;
Properties.Settings.Default.Save();
I plan to add functionalities to TextBox with the following:
public class TextBoxExt : TextBox
{
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
}
}
The question is how can we use this TextBoxExt? Is there anyway to get this class onto the ToolBox so that we can just drag and drop it onto the form? If not, what is the best way to use the TextBoxExt?
Build you project with TextBoxExt, make sure it compiles ok.
With the form that you want TextBoxExt on, open the toolbox, right click and select "choose items"
Browse to you .exe or dll that you compiled in 1)
make sure that TextBoxExt has a tick next to it, press ok
TextBoxExt should appear in the toolbox, drag it onto your form
(There is another way of doing this, opening the designer file and renaming the instances of TextBox to TextBoxExt but manual editing of designer files can be considered hazardous by some)
I know this is super old question, but maybe still useful for someone else that has same problem like me - as it's still on the top Google :)
You might interest to use ToolboxItemAttribute (http://msdn.microsoft.com/en-us/library/system.componentmodel.toolboxitemattribute(v=vs.110).aspx).
I did this at my end to resolve the problem.
[ToolboxItem(true)]
public class PanelTitle : LabelControl {
// Whatever code to override LabelControl here...
}
Rebuild the solution and the extended control should be shown in the toolbox.
Any custom control in your project should show up in the Toolbox automatically. I have found that sometimes the controls won't show until you close a re-open Visual Studio. I assume the issue has something to do with caching of the contents of the Toolbox.
You need to add a constructor to your derived class.
public class TextBoxExt : TextBox
{
public TextBoxExt()
{
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
}
}
Your control should appear in the toolbox for your solution automatically. To have it appear for other projects, you have to do Choose Toolbox items, as others have said.
If you want to provide special design-time functionality, then you will also need to provide some additional designer related attributes and probably your own class derived from ControlDesigner.
I fell into this trap just a couple of hours ago.
I've got a .NET 2.0 Windows Application project with some custom UserControls; it worked fine.
So I decided to order my files in subfolders, to make my project a little bit cleaner.
After that, Visual Studio 2010 designer stopped loading my forms, and ToolBox won't show my controls anymore.
I freaked out, moving back source files in project root, resetting ToolBox, but nothing seemed to work.
After that, I remembered I used ReSharper "Remove Unused References", so I tried to put back unused reference, in particular System.Data: problem solved! :O
I can't say you why, but this worked for me.
Hope my experience can help someone else. :)
Bye,
Nando
I created an empty constructor for my custom implementation of UltraGridBagLayoutPanel. Although david.healed is right it isn't necessary, it is quite useful to put a breakpoint in to check that when the form initialises it is using your class to implement your custom control.
It would have been a lot easier to edit the designer file, but I tried it and changed both the field type for the control and also changed the assignment of the field to a new instance of my custom control.
private Infragistics.Win.Misc.UltraGridBagLayoutPanel ultraGridBagLayoutPanel1;
this.ultraGridBagLayoutPanel1 = new Infragistics.Win.Misc.UltraGridBagLayoutPanel();
to
private Athia.Reports.ultraGridBagLayoutPanel1 ultraGridBagLayoutPanel1;
this.ultraGridBagLayoutPanel1 = new Athia.Reports.ultraGridBagLayoutPanel1();
Doing this destroys Visual Studio every time, and to fix it requires using a text editor to put it back again. Therefore unless anyone can describe what is wrong with my implementation of this approach, perhaps calling the class the same as the control name isn't a great idea, I think the only safe and reliable way to achieve this is as Calanus describes in steps 1 to 5 or as an small deviation from that as Rob Windsor rightly points out restarting VS will bring the control into the Toolbox automatically. Unfortunately for me I then have to change all of the child controls over from the original class to my customised class :-(.
Within the same Solution this should work automatically. However, I have found that if the Target Framework aren't matching the Toolbox does not populate. ( I'm assuming really Reference needs to be of version same or lower than target of Reference. ) ( I did get a warning about non-matching Frameworks )
By making these the same Target Framework, Recompile, Restart VS. the control populated correctly. ( I also added the ToolboxItem(true) Attribute)