Anyone who's done any UI work with .Net and WinForms is very familiar with this type of code:
TestForm frm = new TestForm();
frm.ShowDialog();
I found myself wishing that a call to show a modal dialog was a little less verbose, more like a static call. Andf there is a simpler way. All you really need, in a simple case, is something like this:
new TestForm().ShowDialog();
Am i missing anything? Could there be any repercussions from this kind of shorthand? E.g. windows messages not handled/routed correctly, dialog's resources not disposed etc.?
Was working on this when i saw Ray's feedback:
i suppose an even shorter way would be to create a static member withing TestForm that creates an instance of itself and calls ShowDialog internally. So, this code:
public static DialogResult DoModal()
{
return new TestForm().ShowDialog();
}
could be invoked thusly:
TestForm.DoModal();
If you don't want to reuse the form object anywhere in your code you can just use the short form
new TestForm().ShowDialog();
If you want to do something later with that object then you must assign it to a variable.
Pretty simple. Hide form constructor (make it private), then add static factory method that would initialize new instance of the form and show it straight away.
For example see MessageBox source codes (Mono, if I'm not mistaken)
link
Typical use of ShowDialog should look like this:
using (Form form = new Form())
{
// here setup your form instance
if (DialogResult.OK == form.ShowDialog())
{
// here read data from form instance
}
}
Please be aware that ShowDialog() causes form instance to not dispose itself. You should dispose it manually once you are done with it - hence using clause See http://msdn.microsoft.com/en-us/library/w61zzfwe.aspx for details. In your scenario this should look like below:
public static DialogResult DoModal()
{
using (Form form = new TestForm())
return form.ShowDialog();
}
But this is useful only when you don't need to read any data back from your form instance. So the only scenario that fits here is message box. MessageBox.Show(...) methods utilize pattern you want to implement in your post.
in other scenarios forms are supposed to return data other than DialogResult back to application after they are closed. And that's why standard Form does not have static ShowDialog() or DoModal() methods. Static method should dispose temporal form instance. Such disposal would make impossible to read data back from form. What is more, in static method scenario there is no form instance to read data back from.
Putting all together, your method, to be compliant with guidelines, should look more like:
public static YourResultClass DoModal()
{
using (TestForm form = new TestForm())
if (DislogResult.OK == form.ShowDialog())
{
YourResultClass result = new YourResultClass();
// Here initialize YourResultClass instance with data from form instance
return result;
}
}
But that is very use case specific and quite far from your one-liner utility method.
Related
I am using a RichTextBox which is in a Form that I am basically using as a log window whilst the program performs various functions - much like a debug window. Various methods write to the window as they perform tasks on various files. The simple class looks like this:
public partial class ValidationWindow : Form
{
public ValidationWindow()
{
InitializeComponent();
}
public void writeToWindow(string text)
{
if (richTextBoxValidationWindow.TextLength > 0)
{
richTextBoxValidationWindow.AppendText(Environment.NewLine + text);
}
else
{
richTextBoxValidationWindow.Text = text;
}
}
}
I have instantiated the Form containing the textbox from a class in the usual fashion i.e ValidationWindow valWindow = new ValidationWindow(), then call the show() method to display the window, and i can then write to it using the method in the above class called writeToWindow. All good.
I now need to be able to continue to write to the same window from other classes. I obviously don't want to create more instances of the same Validation Window. So what is the best way to do this please?
It sounds like you need access to this form from other forms and classes. In other words, you need this form to be globally accessible.
The simplest way to do this is add a global variable to your application, and save a reference to the logging window in that variable. Then, if any other class needs to log, it can access the logging window via the global variable.
However, this is perhaps not the best way to do this, as you are tying your logging to that window. What happens if you decide to log a different way? You'd have to change every reference to the window, which means changes all over the application. You would be better off looking at something like messages, which allow the calling code to send out a message requesting that something be logged, but not needing to know anything about the class that receives the message and does the actual logging. I know WOF supports this with MVVM, but am not sure how you would do it in WinForms (assuming that's what you're using). Maybe do a search on "winforms messages" and see what comes up.
Hope that helps
I'm developing an appliaction that has 2 forms and I ran into a problem. When I create a new instance of a class in Form2, then close Form2, I lose the instance values. So, I've solved this using static class, is this the correct approach?
The class name is Matriz_de_registracion and I have a function within it that's called "solver" that assigns values to the class properties ("Double MR0" is one of the variables as an example)
here's the code in Form2 (see I don't use the "new" statement otherwise once I close form2 I loose the instance values..
private void btn_iniciar_registro_de_puntos_Click(object sender, EventArgs e)
{
Matriz_de_Registracion.solver(_pois);
}
Then I can reference, in Form1, one of the properties of the Class by just doing this:
Matriz_de_Registracion.MR0
Now, is this correct approach or static classes are used for something else? I just wan to reference the values of the MR0 variable across all my forms without having to pass the instances through forms every time I open/close forms.
This is not the right approach. You should copy the values from the form object after it has closed but before you get rid of it.
The problem with using static data anything other than extremely sparingly is that you will find it makes the application much harder to work on as it gets larger - for example, you wouldn't be able to open two instances of the form at the same time, as they'd tread on each other's data.
Im using Visual C# 2010 express. Im working on a game, and have come accross a small, newbie problem. Thing is, i guess we're dealing with a best practise type situation, and none of the few beginner books i have really helped with it, so i hope you guys can.
So, i have two forms, one is a splashscreen/startup form and the other is the main game window. I made a class that contains all world data, and when in the first screen user clicks on "new game", a new instance of this class is generated and populated with data.
So far so good.
The newgame button, in addition to creating the world instance, opens up the main game window. The problem is, in the main game window, when i try to use attributes of the gameworld instance, it says that it doesnt exist in this context.
So, if i get it right, the created instance only exists within the first form class... is that correct?
So if i'd like to move that whole data, should i actually serialize and save the world class instance data, and load it in the second form? Or how should i approach this.
I understand it's a very newbie question, and i could propably hack it to work, but the thing is - i really feel like i have to understand everything im doing.
Thanks in advance!
You need to create a constructor on your game form that accepts an instance of your world class and assign it to a field of the same type - the field will be accessible to the game form methods.
World world;
// constructor
public GameForm (World world)
{
this.world = world;
}
// Can now use `world` in all `GameForm` methods
Instead of constructor injection (as I have shown in my example), you can use property injection, though I like the former better (tends to ensure proper initialization - though you may want to check for a null being passed in).
If there is a reference of the world data object in the splash screen, you can assign this to a public member in the main screen, or pass it to the main screen through a constructor.
so in the splash screen
FrmMain frmMain = new FrmMain();
frmMain.WorldData = this.WorldData;
if it is an instance member of the splash screen
or maybe something like
FrmMain frmMain = new FrmMain();
frmMain.WorldData = new WorldData();
or even
FrmMain frmMain = new FrmMain(this.WorldData);
or
FrmMain frmMain = new FrmMain(new WorldData());
with the FrmMain constructor as
public FrmMain(WorldData worldData)
{
this.m_WorldData = worldData;
}
Have a look at Passing Data Between Forms
Assuming you're using just windows forms, and not XNA or similar framework, where theres no winforms.
Startup form:
void StartButton_Click(object sender, EventArgs e)
{
GameWorld gw = new GameWorld();
// Initialize gw instance here
GameForm mainForm = new GameForm(gw);
mainForm.Show();
}
And add a constructor to the game form:
public class GameForm
{
private GameWorld _gw;
public GameForm()
{
InitializeComponent();
}
public GameForm(GameWorld gw) : this()
{
_gw = gw;
}
}
At that point you can use private variable _gw in the game form.
Also, i would suggest passing the GameWorld instance through the constructor, not the property as that value is crucial for the form. Generally properties might be better suited to provide a way to adjust some behavior, and any constructor parameter can be seen as mandatory for the object to work as it should.
You can also make default constructor (the one without parameters) private.
Depending on the size of the data and if the world object class is serializable, You might think about caching it. Then each form that needs the data can just get it from the cache whenever it is needed.
I found so many topics about how to prevent multiple instances of Windows.Forms but I still can't find how to prevent multiple instances for WPF windows. I'll explain my idea. I have a WPF Window. This window have a beautiful custom button. When the button is clicked it opens new window. My problem is that when I click multiple times on the same button the same window appears as many times I clicked the button. How to prevent this? Is it possible instead a new window is opened simply the already opened one to take the focus?
Well you have to check if it is created before creating a new one:
Pseudo like code (only have notepad here)
private YourWindow wnd = null;
void OnButton_Click()
{
if (wnd == null) wnd = new YourWindow();
wnd.Show();
}
I have seen a few methods and this is the one I use. Its in VB but you should be able to convert it to C#. There might well be better ways but I'm no WPF expert!
I have a function tucked away in a module that looks like this
Public Class FormsCollection
Public Shared Forms As ArrayList = New ArrayList
End Class
Public Function Find_form(strForm_name As String)
For Each F In FormsCollection.Forms
If F.ToString = strForm_name Then
Find_form = F
Exit Function
End If
Next
Find_form = Nothing
End Function
Then when I’m trying to open a form the code looks like this
Dim FormToOpen As FormToOpen
If IsNothing(Find_form("FormToOpen")) Then
FormToOpen = New FormToOpen
Else
FormToOpen = Find_form("FormToOpen ")
End If
With FormToOpen
.Owner = Me
.ShowDialog()
.Activate
End with
I tend to use two approaches. Sometimes, I do as PowerRoy suggests and I store a field in a suitably central place in the application which has a reference to the window. If that field isn't null, I activate it instead of creating a new instance.
Sometimes when there are many types of windows but I only want one of each, I use a list of a common base class (List perhaps). Each created window is put in there, and whenever I want to create or switch to one of them, I filter it by type and check if there's anything there and switch to it if there is. Something like:
List<Window> allWindows = new List<Window>();
// ... elsewhere I want to create a ShinyWindow
void ActivateShinyWindow()
{
var shiny = allWindows.OfType<ShinyWindow>().FirstOrDefault();
if (shiny == null)
{
shiny = new ShinyWindow();
allWindows.Add(shiny);
}
ActivateWindow(shiny);
}
Where ActivateWindow() does whatever is necessary to make it visible and bring it to the front or whatever. Actually the biggest thing I've got doing this is inside a tabbed interface, so it's all run by the enclosing shell window.
This is a bit like Kevin Ross' answer, except I'm indexing the collection by type. It obviously doesn't work if you ever want multiple windows which are instances of the same class, and then you're going to want something more like what Kevin did. My strongly-typed functional-programming background says I'd rather use a nice enum to index the windows than a string though.
In an earlier question about how to return a string from a dialog window, yapiskan suggested overloading the child form's ShowDialog() method to include an out parameter.
My question is whether or not this is a good approach in C#.
Here is some example code, based on yapiskan's suggestion. In the child form (in this example, it's a form with a textbox on it), you just need to add the ShowDialog overload and assign UI values to the out parameter:
public DialogResult ShowDialog(out string s)
{
DialogResult result = this.ShowDialog();
s = this.textBox1.Text;
return result;
}
And to show the form and retrieve the entered text, you do this:
using (CustomDialog frm = new CustomDialog())
{
string s;
if (frm.ShowDialog(out s) == DialogResult.OK)
{
// do something with s
}
}
One advantage I can think of is that this approach forces the user of the CustomDialog form to get the information it contains through the form's ShowDialog method (rather than from a who-knows-what-it's-called method like GetMyData() or something).
Better to have a Public property/method and get the information.
What would you do if you would need 3..4..5 informations, having 5 parameters out? More clean to have accessors to get your information from the Dialog.
It should not be OK since .net framework does not use this design. In the case of OpenFileDialog class, it has a parameterless ShowDialog() method returning a DialogResult. Once this method called, user is supposed to get the selected files by using the FileName, FileNames, SafeFileName and SafeFileNames methods.
Let's assume that this implented in the "out parameter" way. I would have to write code like this just to get the SafeFileName:
string dummyFileName;
string[] dummyFileNames;
string safeFileName;
string[] dummySafeFileNames;
myDialog.ShowDialog(out dummyFileName, out dummyFileNames, out safeFileName, out dummySafeFileNames);
Personally I try to avoid out parameters wherever possible, although I understand that like GoTo they are sometimes a necessary evil. I would say that it would be much better to use properties or methods to return the information.
In my experience, a custom modal dialog that collects only one piece of information is a pretty extreme outlier. Much more common are zero and many.
And a dialog that collects many pieces of data is almost certain to be modified at some point to collect just one more. I'd much rather fix only the code that uses that one new piece of data than every single piece of code that uses the modified dialog.
Also, think about how a developer uses IntelliSense to use your class. He's going to type this:
MyDialog d = new MyDialog();
d.ShowDialog(
...and at that last keystroke, IntelliSense will pop up telling him that he now has to declare three new string variables to hold the out parameters. So he moves the cursor up, and starts typing:
string foo;
string
...and, what was the name of the second parameter again? So it's back down to the open paren, hit CTRL+SPACE, oh yeah, it's bar, back up to the previous line, etc.
The problem with using properties on a custom dialog is that the Form class already has a million properties, and the three or four special ones that you're creating are going to get lost in the mix. To fix this, create a class for the dialog parameters and a Parameters property of that type on the custom dialog. That makes code like this easy to write:
MyDialog d = new MyDialog();
d.Parameters.Foo = "foo";
d.Parameters.Bar = "bar";
d.Parameters.Baz = "baz";
because the parameter names pop up in IntelliSense, and you don't need to declare any variables to hold their values.
My approach is typically to write a method that internally calls ShowDialog, then formats the output data appropriately. For (contrived) example:
public string GetFolderName(){
if(this.ShowDialog() == DialogResult.OK) {
return this.FolderName.Text;
}
return String.Empty;
}
In most cases I make this method static, and instantiate the dialog itself from within the body of the method - that way the caller doesn't have to deal with form references, or the notion of having to chose which 'show' method to call.
In the non-edge cases of having multiple output values, I typically construct a struct that holds these values, then have my 'Get' function return that struct.
public struct FolderData {
public static FolderData Empty = new FolderData();
public string FolderName {get; set;}
public int FilesInFolder {get; set;}
}
public FolderData GetFolderData(){
if(this.ShowDialog() == DialogResult.OK) {
return new FolderData {
FolderName = this.FolderName.Text;
FilesInFolder = int.Parse(this.FilesInFolder.Text);
}
}
return FolderData.Empty;
}
I prefer this one because I don't like the approach of getting result from a property or a method after you have done with the class. After dialog form was shown and closed I think the object should not be used any more because logically you have done with the dialog then why should I use its property or method to get the result?
#Musigenesis, you really don't want to force client code to break when you change your dialog, and using an out parameter that is only sometimes valid isn't a good design. As #Daok says, when you have more than 1 value returned this starts to get messy and ugly fast.
You also can't force client code to use the result any more than the .net framework ensures that you call properties on a file dialog. You're also not forcing the caller to do anything with the out parameter, all you've forced them to do is to accept a variable that they may not want to use.
If the dialog is very generic this may not be applicable, but instead of chucking all sorts of properties to the dialog itself, have a single method that you use consistently throughout your application, and have that return a specific class that holds the relevant data.
public sealed class MySaveDialogResult
{
public static MySaveDialogResult NonOkResult(); // Null Object pattern
public MySaveDialogResult( string filePath ) { ... }
// encapsulate the dialog result
public DialogResult DialogResult { get; private set; }
// some property that was set in the dialog
public string FilePath { get; private set; }
// another property set in the dialog
public bool AllowOVerwrite { get; private set; }
}
and your dialog is
public MySaveDialog ...
{
public MySaveDialogResult GetDialogResult() { .... }
}
The essence is a small immutable utility class that also implements null object pattern. The null object is returned whenever the dialog result wasn't OK. Obviously the above is a shot in the dark for your needs, so alter it at will, make inheritance hierarchies, etc.
The main point is to have GetDialogResult(), a single method on the dialog, to returned a class that encapsulates all the relevant dialog data.
edit:
#yapiskan wonders why not just 'out' the MyDialogResult versus calling GetDialogResult().
IMO - The points are simply:
That's not the convention
A method call is trivially easy, and made easier when you follow the 'convention' argument as made above.
out is awkward to use. GetDialogResult() is not forcing the caller to write awkward code, and it doesn't force the user to consume the dialog result at the point of invoking the dialog.
Normally the dialog isn't re-instantiated or re-shown to get the result, it's already there. Show() and Hide() do just that.
The reality is you're trading a method call for an awkward ShowDialog() syntax. Method calls are cheap, and you can't guarantee the caller will use your out parameter any more than you can guarantee they will call GetDialogResult(). So why bother. Make the thing easy to use, or don't overload ShowDialog in the first place.
Maybe whatever you're sub-classing is funky and acts differently and it's not applicable to your situation, but general design is forms don't go away when you click OK, they go away when they are Disposed() of.