I have an application that can launch/new up a form(lets call it QuickNoteForm) from many different actions. It can launch the form from many different tabs and mostly are launched thru buttons all over my application.
I basically want to track where it was launched from, ie I need to track its Launch Path.
What would be a good approach to implement this. I was thinking to enclose this as a property that gets set via the constructor of the QuickNoteForm. I want to track from which action this form got launched from.
This is a windows forms application and not a asp.net app.
thanks.
Create an enum that would list all possible paths (or a static class with constants if you worry about maintainability, enums don't work well when compiled and then modified). Add a custom constructor to your form that would accept this enum as a parameter. When you instantiate a form, use that constructor. Basically replace all occurrences of New QuickNoteForm() with New QuickNoteForm(yourEnumValue). For compatibility, add an Unknown = 0 value to the enum, this way calling form's default constructor will work too, just not as useful.
If this approach is not practical (please provide more details on your application), you can also provide a context Control as parameter in your form's constructor. Then have code like If typeOf ctl Is Button AndAlso DirectCast(ctl, Button).Text = "Something" Then and all sorts of crazy stuff. This promotes separation of concerns, i.e. the calling code does not need to know how to call and only pass itself as a parameter, but also makes your code harder to maintain, because you may end up with one giant know-it-all method which would connect all pieces together.
Related
I have a Winform .dll referenced inside my WPF project. Main method of .dll has a parameter for passing a Control object. I need to pass reference of WPF Button control inside that method parameter, but I receieve error : "Value of type 'Button' cannot be converted to 'Control'".
As far as I've seen I can't do that because WPF and Winform controls are entirely different things, but Is there anything I can do ?
P.S.: Main .dll method opens WinForm window next to specified control (WPF control in this case), that is why I need reference of WPF control.
Honestly, the best, easiest, cleanest solution is to make another version of the Main method which accepts System.Windows.Controls.Control instead of System.Windows.Forms.Control. They can even be overloaded (share the same name). The changes to this new version would probably be very few and simple.
However, assuming Main is some huge, complicated method that would be a nightmare to even look at- or you don't have the source code anymore- and you really have to use the existing method, there is one other potential option:
Make a class that inherits from System.Windows.Forms.Control which will act as a wrapper around a System.Windows.Controls.Control. You can use new and/or override keywords to replace the existing properties in System.Windows.Forms.Control and instead expose the equivalent properties of System.Windows.Controls.Control.
To give a rushed example:
class WinformsControlWrapper : System.Windows.Forms.Control
{
protected System.Windows.Controls.Control WrappedControl;
public WinformsControlWrapper(System.Windows.Controls.Control wrappedControl)
{
WrappedControl = wrappedControl;
}
public new int Width
{
get { return (int)WrappedControl.Width; }
set { WrappedControl.Width = value; }
}
}
Of course there are numerous problems even with the above example: the fact that WPF uses double and winforms uses int, and the fact that WPF has both Width and ActualWidth to name a couple. But you should probably be able to write your class to work the way you need it to.
Again, making another version of Main is a much simpler, cleaner and probably easier solution. But if you really can't the above tactic should work.
My solution was to change Main .dll method. Instead of passing Control object I changed parameter to accept Point object - which Is what I need in the end from a control, to get their X and Y coordinates... However WPF and Winform uses different Point library references (System.Drawing.Point and System.Point) which are different types so when calling .dll in WPF I had to convert WPF Point object into type that Winform System.Drawing.Point accepts. That was easiest I could come with.
I grew up on VB.Net. From there, in a routine, I could instantiate a form, and access controls that I had put on that form, like a textbox. Further, after hiding the form, I could read public properties that got set on the form. I am trying to do this in C# and according to the intellisense, neither is accessible.
so, in Form 1, for example I say
Form f = new MyOtherForm();
from there, f only returns things like Text, or Tag.....I can't see any controls on f to set them.
Further, MyOtherForm has a public property called MyResult. After a show dialog, in VB.Net, I could, from the calling form, access
f.MyResult
In C#, I cannot.
Can someone help me understand how it works in C#?
If you want to see the properties of MyOtherForm, you should declare the form as MyOtherForm:
MyOtherForm f = new MyOtherForm();
Beside that, you should also check if the property you are looking for is set as public.
To make your life easier, learn and love the var keyword.
The implicit typing that this introduces allows for you to not have to worry about getting the correct type when declaring a variable. In your case, you know exactly what you're setting it to, so it isn't a huge deal. However, when you're getting results from methods, or LINQ calls, this provides a huge benefit.
Bear in mind, this isn't like the var keyword in JavaScript. Your variable still has the correct type, only you don't have to set it explicitly.
I found that I can either pass 8 arguments to a class constructor or just pass the form variable instead.
However, since I am not using everything on the form it seems like it may be bad design?
Also, the objects I do access I would need to provide accessors for.
Does it violate the principles of OOP?
It depends - if you're using the form as that specific type of form, and "logically" it makes sense that you're working with the form, then by all means, pass a reference to the form.
It's just like any other class - If I was going to be accessing elements of an "employee", I'd write:
void DoSomething(Employee employee) { ...
Instead of:
void DoSomething(string firstName, string lastName, DateTime hireDate...) { ...
The first is very clean and obvious.
However, if the data you're using is unrelated to the form, it'd be better to encapsulate it into its own class usable by both the form and your class.
Also, the objects I do access I would need to provide accessors for.
If this is the case, I suspect that having a class encapsulating the data is likely a better design... The form could expose a property or method that returns an instance of that class, and pass it into your second class.
Passing a gui form to either other gui components or even worse, a model/library that does work does break encapsulation and creates a tight coupling.
The form should abstract the data and the model below. Other model or library classes should be passed model objects. A typical pattern is to "bind" the gui layer to the model.
Instead of passing 8 variables, do the 8 variables logically break into different objects? Ideally, you would pass an object or set of objects which may collectively contain 8 member variables. Then you can simply pass references to objects that are contained in the same model that your gui is abstracting and bound to.
Without seeing the class, I can almost guarantee the class taking 8 arguments is violating the Single Responsibility Principle. It could be a class generated to represent a table in a database (or something to that effect) in which case you should encapsulate it in its own class as pass it around instead of the form.
Something else to consider is that the form you're reviewing is also violating SRP since it's both displaying data and being used as backing for another form.
It typically is, because typically people are lazy or don't understand how to use events, so they write code like this:
class MainForm : Form
{
// stuff
}
class ChildForm : Form
{
private MainForm _mainFrm;
public ChildForm( MainForm frm )
{
_mainFrm = frm;
}
private void someButton_Click( ... )
{
_mainFrm.UpdateSomeText();
}
}
That code creates a terrible coupling between two different UI classes. Now, in a simple, internal, maybe throwaway project it is probably fine and you can write it once and move on. In general it means that you very well may need to change your ChildForm class in response to changes in your MainForm class, which is undesirable and can be avoided via weak coupling mechanisms like events.
On the other hand, there are valid cases to pass in a form to a method or constructor, though these situations are less common in practice. It all boils down to what you code is doing and if it is optimally designed. There is no rulebook for this, it takes years of practice and requires that you make many mistakes first so that you know what to avoid before writing any code at all.
I can imagine a class that controls the formatting of a form (font, size, color etc) that could take a variable of type Form as an argument. I could argue that THAT structure wouldn't violate OO principles. Anything short of that probably not.
Even if you need customer details in the new class and you're tempted to pass the CustomerForm, which contains all the details you need, DON'T DO IT. Create a customer class, provide an instance of that class from the form and pass that instance to the new class instead. If you ever change the UI, or if you ever need to automate part of the workflow that used to be manual you'll be glad you did.
At the moment my Form1 code is extremely heavy, mainly full of menu and control events. One thing I would like to do is organize it in some way, so I could expand or collapse "related code" (in Visual Studio).
My first attempt at this was to put code relating to the main menu, for example, inside a nested class called "MainMenu", which was within the Form1 class, so that I could simply collapse the nested class when I don't need it. This resulted in all sorts of problems (i.e. I couldn't find a way to set up the main menu inside this nested class).
Is there a simpler solution to this that I'm missing? Or can someone shed some light on why my nested class idea is faulty?
While #testalino's answer certainly does what you ask for, I would say that your real problem is probably related to code design. Chances are that the form class simply contains more code than it should, and that some of it ought to move into other classes.
If done in a good way, this might give you some benefits:
You will likely get more encapsulated (and less coupled) behavior, when various functions operates on data passed to the methods through parameters and return values instead of fetching and setting values directly in UI controls.
You might get a more testable code base (you do have unit tests, right?).
It will be easier for several persons to collaborate on the code, since the code is spread across several different code files. This reduces merging conflicts (you do have a source control system, right?). This point may not be as applicable if you are working on something alone, but it doesn't hurt to have this habit anyway.
You can use #region and #endregion to organize code within a class. These regions are then collapseable.
I suggest you using User Controls to encapsulate some of Form's behavior. This is the simplest solution available for you right now, I guess. You just pick some piece of user interface and extract it to user control and define some public properties accessible from the form.
Keeping all handlers in Form.cs is a bad, bad practice. You must avoid it because it's unmaintanable (I've seen much code like that, and at later stages adding or changing functionality is proven to be impossible without breaking anything, let alone changing the UI without affecting the way app works).
In future, you may want to try different approaches to separation UI from application logic, e.g. explore MVP/MVC patterns.
If your form has become so big and complex that you suddenly desire to organize it in some way it is a strong hint towards the need of refactoring, which will improve readability, testability and maintainablity of your code. How you actually refactor depends upon your actual code.
Is it a form that has a lot of controls? Think about splitting it up in separate UserControls where each of them displays a certain aspect of your domain data. Do you have a lot of interaction logic, reacting to a lot of events? Maybe introduce a some sort of Controller or EventAggregator.
There are a lot of well known patterns that can help you organize your UI and domain code. This series talks about just that and introduces you to patterns MVC, MVP, EventAggregator and much more. It discusses the patterns in the context of windows forms just as you need it.
Use the partial class keyword in order to split your class into several files.
I agree with what the other answers say about grouping alike event handlers together in #regions is solid given a massive number of events. In addition, if the code itself in the handlers is voluminous as well, you might want to think of refactoring those into logical business logic classes. Example:
pseudocode before:
private void SomeButton_Click(...)
{
using (FileStream fs = ...)
{
fs.Write(some form data);
fs.Write(some more form data);
}
DoMoreBusinessLogicStuff();
...
// lots more stuff
...
}
pseudocode after:
private void SomeButton_Click(...)
{
IBusinessObject obj = new BusinessObject(injectable form data);
using (IPersistence store = new FilePersistence(...))
{
obj.Persist(store);
}
obj.DoBusinessRules();
}
This should move business, persistence and support logic to their own classes and leave your event handlers as lightweight shells designed only to gather UI input and pass it along.
Nested classes are generally frowned upon as being only a slight upgrade from god-classes for one thing, and encapsulation and code reuse being pretty murky.
You should be aiming to express the objects you actually have as individual business classes within your code: one class, one file. Is there any particular reason you aren't doing this?
Depending on the type of code it is doing will depend on where you can move it.
If its processing data code then you can move this out into separate classes in a different namespace returning the processed data to controls to allow for data binding etc.
If Form1 is getting very heavy with code then is this because you've got too much going on in Form1? Could you break it out into a different/new form?
You could use the summary which is collapsible but I think this is more intended for providing other developers with information, always good practice though!
In VB:
''' <summary>
'''
''' </summary>
''' <remarks></remarks>
In C#
/// <summary>
///
/// </summary>
/// <remarks></remarks>
I've started using this alot to link elements of my UI to their data backing class (whatever that might be). What are some of the common uses you put the Tag property to use for?
Indeed, do you use it at all? I know I didn't for a very long time.
Just as you describe, the most frequent use of the Tag property I have come across and use in both WinForms, WPF and Silverlight is to indicate the real data that the control relates to. This is especially useful on ListViewItem instances or auto-generated user interface where you want to use the same event handler for multiple objects where only the target data is different (i.e. the action to be performed remains the same).
However, I have also used the Tag to store an enumeration value (though you should avoid value types as it would cause boxing when assigning the value to the Tag property) or a string that is then used to determine the action that needs to be performed instead of the data on which to perform it, and in one particular usage, I stored a delegate so that I could auto-generate some buttons and embed their handlers in the Tag (the handler information was supplied in a data driven manner).
I am sure there are many other ways to use Tag and many other ways to replace the uses of Tag with something more strongly typed, but that's how I've used it.
The Tag property is an ancient (in programming language terms) hold over for controls. To my knowledge, it's been used in everything from visual basic, delphi, and pretty much any other gui based language.
It is simply an extra property that allows you to add a numeric value for any reason you want to the control.
I've seen it used for everything from a counter to holding a record id that the control is tied to.
It is a bit of a kludge. It is often used in for instance a TreeView to link a Node to a data element.
But I would not over-use it, since it is very public and not very flexible. Note that you can almost always use a Dictionary< Control, ValueType> instead, and have a lot more control that way.
I use it all the time with ListViews and TreeViews. It makes trying to find the underlying data much easier. In fact, I'm not sure how you'd make a readable Winforms application without it.
I also use it a lot when creating ContextMenus at run-time. I stuff an object into the Tag member of each ToolStripMenuItem and then I can point each menu item's click handler at the same method. It results in a lot less code.
I just wish it didn't require so much casting.