WPF using statement to open another form - c#

I wrote a C# app in Winforms and am now rewriting it in WPF. In the Winforms version I used the following to open another window while sending it information and receive information back from it:
using (showSelection showSelection1 = new showSelection(listBox2.SelectedItem.ToString()))
{
showSelection1.ShowDialog();
storage1.showID = showSelection1.showID;
storage1.numOfSeasons = showSelection1.numOfSeasons;
}
This worked fine, I sent the selected item from listBox2 and received showID and numOfSeasons using this code in the showSelection form:
this.showID = Convert.ToInt32(dataGridView1[2, dataGridView1.CurrentCell.RowIndex].Value);
this.numOfSeasons = dataGridView1[1, dataGridView1.CurrentCell.RowIndex].Value.ToString();
this.Close();
Now, in the WPF version I try the same thing:
using (ShowSelection showSelection = new ShowSelection(showListBox.SelectedItem.ToString()))
{
}
But inside the using( ) I get this error:
ShowSelection: type used in a using statement must be implicitly convertible to 'System.IDisposable'
I'm not really sure where to do from here. Can I fix this and still go about it the same way or is there a different way I should be doing this? The ShowSelection window is just a datagrid with a single button.

WPF components don't use Win32 handles (Window does, but it self-manages), so they have no need to be IDisposable, and you have no need to Dispose them or use them in a using block.
Once there are no more references to your Window it'll be marked for collection by the GC, same as other pure NET components.
In case you want to use it within a using block, you can implement IDisposable on your window manually, but it's indeed not needed.
In case you want to manually remove resources (and keep using it in a using block), then the simplest you can do:
public class ShowSelection : Window, IDisposable
{
public void Dispose()
{
/* here you'd remove any references you don't need */
}
}
But unless there's a need for it, I'd advise against doing so

it's simply says that ShowSelection class do not derive from IDisposable
so use it without the using:
ShowSelection showSelection = new ShowSelection(showListBox.SelectedItem.ToString());
and than access the properties you need to:
showSelection.#####

Related

Why can't I use data created in my constructor in Windows Forms?

I am trying to create a Desktop Application that is basically a pet orphanage for people to donate and receive pets without home. I created my database and my design for the app, but my progress is blocked by the fact that whatever variables, parameters or anything I create inside the public : Form2 ( ) constructor cannot be used inside the rest of the code. I have multiple tutorials that I follow for the moment in order to create my application, and all of the use the same approach ( Create database connection inside the constructor of the form, where InitializeComponents() is located, then use that same connection throughout the code ).
I seem to encounter an issue that basically stops me from using anything created inside the constructor ( image below ).
This is stopping me not only with the connection. For example if I create an instance of an User Control like this:
ucHome home1 = new ucHome();
home1.BringToFront();
Everything is working fine and the UC is brought to front but if somewhere in the code ( anywhere ) like a Button-Click function I try to use the method home1.SendToBack() for example the code will not recognize home1 and will tell me it is undeclared.
Any ideas of how I might fix this?
Thank you!
You can pass the sql context at GetData method because actually your context scope is only the constructor.
Try this
private void GetData(MySQLConnection sqlConnection)
{
// Data find
}
Do not forget call GetData method on form2 constructor.

The variable is either undeclared or was never assigned

I'm refactoring my code to implement multi-database work. I use System.Data.Common classes and factory to create Exact objects for currently selected database engine. Some connection definitions in Designed looks like:
private System.Data.Common.DbConnection cn;
and assigment is:
private void InitializeComponent()
{
...
this.cn = SqlFactory.CreateConnection();
...
}
and SqlFactory code looks like:
public DbConnection getConnection()
{
return (TSqlConection)Activator.CreateInstance(typeof(TSqlConection));
}
It works okay at runtime, but when i'm trying to open any form in VS Designer i've got errors like the following:
The variable 'cn' is either undeclared or was never assigned.
And Designer can't display form for editing.
How can i fix it?
The InitializeComponent method should not be touched manually in general, the Form Designer always overwrites its contents once you open it. Visual Studio usually adds an autogenerated comment about that in *.Designer.cs. Also, I would suggest not to try to create any DB connection in the default constructor (the one without parameters), because Visual Studio calls it when you attempt to open your form in the Designer.
So, your options are
Create an additional constructor for your form with parameters, this one can try to initialize your DB connection.
Use the Load event of the form.
Create an additional method called, for instance, InitConnections in the form, this method will perform a necessary initialization. You call it right after your form is created somewhere in your code.
Remove this.cn = SqlFactory.CreateConnection(); and everything about cn from Designer.cs.
Add this part after InitializeComponent();.
Now you can edit form and no errors will occurre.

Casting as a form from a window handle

My C#.NET Windows application dynamically creates a bunch of forms with no name and no borders, this works fine, however I later need to find these forms and set them to be the top most forms. My current logic is to write the myForm.Handle to a string at the time of creation so I can refer to that handle later.
And this is where it fails, when I'm ready to set it to be the top most windows, I do this:
Form myForm = Form.FromHandle(sFormHandle);
if (myForm != null) { myForm.TopMost = true; }
The sFormHandle is a string and it expects a IntPtr, how can I convert it, or do this in some other way?
Many thanks.
The Handle property on a form is an IntPtr.
Why have you stored it as a string?
The solution here is to store the handle as an IntPtr, not a string.
Better than that, if this is all .net windows forms code, why not keep a reference to the form rather than the handle?
Edit: added emphasis. Consensus from community seems to be that references to the forms should be retained and the handles should not be relied upon.
Form fr = (Form)Form.FromHandle(new IntPtr(int.Parse("0")));
and beware of direct refrence to a class...
you better try WeakRefrence because of COM class models
if you use a direct refrence to a class,
the class will not unload till all the refrences are removed!

Avoiding magic strings and numbers

I am working on an application that has been edited by various programmers over the past few years and I have stumbled across a problem with using String Literals to access MenuItems.
For Example: in many places there is code like
mainMenu.MenuItems[1].MenuItems[0].Visible=true;
or
mainMenu.MenuItems["View"].MenuItems["FullScreen"].Visible=true;
how do I change the Strings used to identify the MenuItem and catch all of the places that it is being used for access? The menus and menuitems are declared as public and are used throughout this large application
What is the right way prevent the use of these magic indexes from being used. I forsee things being broken everytime a new item is added or the name is changed.
P.S. I have started using an enumerated dictionary approach in which every menuItem is paired with a key. but this still does not force other developers to use my implementation nor is it the most elegant solution to question 2
Give each menu item a name in the WinForms designer (I assume), and then refer to it by that name.
Then just use this in your code:
menuExit.Visible = false;
If the menu items are added programmatically, do this:
class MyForm : Form
{
private MenuItem menuExit;
...
myMenu.Items.Add(menuExit = new MenuItem(...));
...
}
and then still access it by the menuExit name. The key to avoiding magic numbers and strings is to just keep a direct reference to whatever it is you want to refer to. As a bonus, you can now rename this vairable safely using F2.
Romkyns answer is the correct one for this scenarion however if you do need to use string literals in your code I would alwasy keep them in public static classes such as:
public static class Constants
{
public static class Menu
{
public static readonly string FirstMenuName = "Menu 1";
...
}
public static class OtherCateogry
{
...
}
}
You can then access them by Constants.Menu.FirstMenuName.
As for definitively preventing other devs from using literals throughout code - you might have to make recourse to the Rod of Correction (sturdy metal ruler) ;).

Adding a visual behavior to multiple forms

I want to add a specific behavior to multiple forms. In this case its a balloon message that is triggered when a field fails input validation. The easiest solution I could come up with was making it a static class and calling it in the failure condition of each field's onvalidate event.
public static class BalloonMessage
{
private static ToolTip _toolTip = new ToolTip()
{
Active = false,
IsBalloon = true
};
public static void Show(string message,Control control)
{
if (!_toolTip.Active)
{
//4 year old bug in tooltip doesn't place balloon "tail" correctly
// when first attached to a control. Microsoft still hasn't fixed it.
_toolTip.Show(message, control);
_toolTip.Active = true;
_toolTip.Show(message, control);
}
}
public static void Clear()
{
_toolTip.Active = false;
}
}
private void textBox1_Validating(object sender, CancelEventArgs e)
{
if (textBox1.Text.Contains(" "))
{
BalloonMessage.Show(String.Format("Field cannot contain spaces"), textBox1);
e.Cancel = true;
}
else
{
BalloonMessage.Clear();
}
}
This allows me to use the BalloonMessage in any form without requiring an explicit dependency but I'm wondering if this is the best approach. The sample code doesn't show it but the production code uses numerous interrelated MVP triads. The validation is being done in the presenters, which don't have direct access to any of the forms' controls. So I'll have to pass the validation result and any error message back to the view for displaying in a balloonmessage.
By the way, if your wondering why I'm using a tooltip instead of wrapping EM_SHOWBALLOONTIP its because I wanted this functionallity on Windows 2000 and EM_SHOWBALLOONTIP was added in XP. Tooltip can be displayed as a balloon in 2000 as long as IE 5.5 or greater is installed (all my Win2K clients are using IE 6). I'm simply keeping it inactive until needed to inhibit its default on hover behavior.
I would say that this is probably the way to go. It follows the MessageBox functionality built in to .NET.
You could create a base BalloonTipForm that your other forms inherit from with the elements that you need. You still wouldn't be able to handle validation events for specific controls in it, but you could certainly have general methods for displaying it.
And I'm sure there's some sort of way you could rig it to observe your actual validation so that you may not have to explicitly call the balloon show/hide methods. (I don't know whether the actual validation in your presenters would require multiple such calls or can be just a few.)
Your own solution doesn't look too bad, either. You could easily mix the 2.

Categories