What the best way to save/load Windows Forms ToolStripMenuItem - c#

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();

Related

How to use resources in C# Visual Studio? [duplicate]

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;

Raise PropertyChangeNotification on Property in different class (different ViewModel)

Motivation:
I'd like to have a 'File->Save As' MenuItem that behaves just like in Visual Studio. When there is nothing opened it says "Save Selected Items as..."
and when a particular file (e.g. SomeFile.cs) is opened in a tab, the MenuItem reads "Save SomeFile.cs as...".
My App architecture (MVVM, using MVVM Light):
MainWindow.xaml:
<MenuItem Header="{Binding SelectedProjectName}" HeaderStringFormat="Save {0} As..." />
MainWindowViewModel:
I hold a collection of opened tabs (opened files)
private ObservableCollection<BaseProjectViewModel> _projects;
I have a property returning a currently selected tab
public BaseProjectViewModel SelectedProject
{
get
{
return _selectedProject;
}
set
{
if (_selectedProject == value)
{
return;
}
_selectedProject = value;
RaisePropertyChanged("SelectedProject");
RaisePropertyChanged("SelectedProjectName");
}
}
I created a property returning the name of the file in the currently selected tab
public string SelectedProjectName
{
get
{
if (SelectedProject == null)
{
return "Selected Item";
}
return SelectedProject.SafeFileName;
}
}
BaseProjectViewModel serves as a base class for various file types. Each file type has its own class derived from BaseProjectViewModel. It has properties like for example
PaneHeader that returns a string to be displayed in pane header,
SafeFileName that returns just the file name of a path etc...
Question:
When I change the name of the file (thus changing properties of the BaseProjectViewModel) how do I trigger RaisePropertyChanged of the SelectedProjectName in MainWindowViewModel?
What is the cleanest way to do that?
My thoughts
I thought of two possible ways to do that, but i don't know if any of them is the correct way to do it:
(In short) Listening to CollectionChanged on _projects. When there is add/remove -> subscribe/ubsubscribe an event handler that would
look if the PropertyName is the one we are looking for and if yes subsequently call RaisePropertyChanged("SelectedProjectName")?
Use something like MVVM Light Messaging.
Question 2: If you don't suggest any other way and in fact you'd suggest one of these two - could you please elaborate on advantages and disadvantages?
EDIT
I created a very simple project to demonstrate the issue - LINK.
When you run the project:
'New' adds a new TabItem. When text is edited, the TabHeader is decorated with an asterisk.
'Save {0}' menu item "saves" the selected TabItem (simulated by removing the asterisk). I didn't want to complicate the example and introduce a SaveFileDialog and such.
'Save As {0}' menu item simulates Save as in such a way that it adds 'X' character to the end od Tab header string.
When no TabItem is selected, the {0} resolves to "Selected Item".
When you have one tab selected, you click SaveAs() and open the menu, you'll notice that change has not been raised on SelectedProjectName property. When you click another tab and then select the first one back, the change is propagated.
Edit for Erno: What I fail to understand is this: Let's suppose I have a special menu for each document type. Let's suppose I have one particular tab selected (with it's own menu enabled/visible, the other collapsed). How is it going to help me propagate the PropertyChanged of PaneHeader property in BaseProjectViewMode to SelectedProjectName in MainWindowViewModel? If you have time could you please demonstrate it on the example? I also would like to ask you what would be an alternate way if I wanted/neede to do the wiring? Thank you in advance.
From your options I dislike #1 because it might introduce a lot of wiring that is hard to track and maintain.
Option #2 might be OK but could end up in the same wiring mess as #1 but because of the messaging it will be less visible.
I'd consider a different approach:
put a menu in the MainWindow that is responsible for handling commands when no files are open or selected.
when a document is opened in a view and has the focus: replace the current menu with the document specific menu. (like MDI applications work in WinForms)
This way you can customize the Menu per document (type) and it does not require the event dependencies.

Controls on Form Not Shown in Designer

I am working on a WinForms project, and I have a form where I have a DataGrid, a TextBox, and 2 button controls (btnNew and btnSearch). The click event of a btnSearch is supposed to perform a search on the DataGrid.
I deleted the event handler for the search button and have saved my work. It now appears that all other controls have been deleted and the form is back to the default state. The application works fine though when run, with some errors. I have resolved the error but the designer view is still in the default state. How do I go about reinstating my form's design view?
i had your problem and solved it in this way:
just make another form with another name(NewForm.cs) and copy the InitializeComponent() content from YourFirstForm.designer.cs and paste it into
NewForm.designer.cs InitializeComponent() function. but be careful when copy and paste the function content change all YourFirstForm keywords to NewForm . finally Remove YourFirstForm and just work with your NewForm....
With the control selected in the properties window.
Right click on an empty space on the form,
Click cut
Right click / then paste into a cell somewhere in a form control.
I've run into errors like this before where simply closing all the form's files (code view + design view) re-open the code view and then Shift-F7 to reload the design view would fix it.
If that doesn't work perhaps fixing the error you mentioned in the designer view caused something to get out of whack. Try comparing the structure in the YourForm.Designer.cs file with a new form to see if an inadvertent edit was made.
i had your problem in Visual Studio 2017 and solved it in this way:
-select controls by Properties
-view Location is -
-change the Location
-drag the control to another location
Make sure all errors related to form are removed and your code compiles successfully.
If Form has been copied from an existing project make sure Form.Designer.cs and Form.resx are under same parent Form.cs and not separate. Check Form tree in Solution explorer. If they are not under the same tee, load the designer.cs and .resx file again in the project.

Silverlight business application initialize check

I am using the Business Silverlight application. I have incorporated some MVVM into this and were off an running with it. We are using some telerik controls, mostly the ribbon control and the docking. We register all the telerik ribbon controls in the about.xaml.cs file, the method is DisplayUI - its here where we register the docking control then we register the ribbon after this. What happens is that when you click the ABOUT link it shows our first tab with buttons(perfect). when you click the HOME link next to the ABOUT link, we go back to the home page..but when you click the ABOUT link again it registers the controls again so we end up with two tabs that are the same.
Is there a way to check to see if this about.xaml.cs file has already been initialized? Im guessing that is has a handle on the first call in memory as I am able to see the first tabs rendering..
Thanks
here is the about code
public About()
{
InitializeComponent();
DisplayUI();
this.Title = ApplicationStrings.AboutPageTitle;
}
that display UI does all the work in registering the dockpanel and the ribbons. We'd like to not have the DisplayUI() called if this has already been rendered once.
If you do it by event handler can you unsubscribe from the event at the end of the method? Without seeing some code it's hard to work out what to change.
It's not the nicest way of doing it, but if this code needs to run once and only once then you could have a static boolean variable on the class set to false and when you call DisplayUI you check the value of this. If it's false you set it to true and run the method, and if it's true you just return.

How to save user inputed value in TextBox? (WPF, XAML)

How to save user inputed value in a TextBox? (WPF XAML) So in my xaml window I have a TextBox. A User starts my application, inputs some values into it and presses a button or hits Enter. He closes the app, opens it up again. How to make his inputs to be saved in that TextBox in WPF?
You can use the built in .net settings.
In visual studio, right click on your project and choose Add new item. From the dialog, select "Settings file", and give it a name like "MySettings". Visual studio will create a few files including a MySettings class with some static methods to provide you access to your settings.
If you open this file up, you will be given a nice grid ui that allows you to enter some settings, set their type (in this case String) and set a default value. It also allows you to specify if they are application or user settings.
Application settings: Cannot be modified after the app has started. Can only be configued by editing an xml .config file. Will be the same for every user who runs the app.
User settings: Can be modified and saved while the application is running. Will be stored in the users documents and settings\username\local settings folder. Can be different for every user.
For what you are describing, choose "User" for the scope.
Now, to access the value in code:
// Load the value into the text box.
txtBox1.text = MySettings.Default.SomeSetting;
and to save a change:
// Update the value.
MySettings.Default.SomeSetting = txtBox1.text;
// Save the config file.
MySettings.Default.Save();
There's more information about all of this on MSDN here, and there is more information on the ApplicationSettingsBase class here.
(Obviously, if you are using mvvm, or any other UI pattern you can adapt this code to load the settings values into your model/viewmodels whenever it's appropriate rather than directly into the text box)
In addition to what Simon said, WPF also allows you to bind your UI controls directly to your application settings. That way you don't have to manually load them. Just import your project's Properties namespace into the Window or UserControl and use standard Binding syntax. Here I have defined a User-level setting in my project's Settings named ServerURL. Here is how I bind to it.
<Window x:Class="YourProjectNamespace.SomeWindow" xmlns:props="clr-namespace:YourProjectNamespace.Properties">
<TextBox Text="{Binding Source={x:Static props:Settings.Default}, Path=ServerURL}" />
</Window>
Remember that you still need to call Settings.Default.Save() at some point, probably upon Window's Close or whatever is appropriate in your case. Two-way binding DOES update the source automatically (which in this case is Settings object), but doesn't write it to disk. You have to call Save() for that purpose.

Categories