This question already has answers here:
Communicate between two windows forms in C#
(12 answers)
Closed 3 years ago.
Throughout my time coding in the realm of C# WinForms, I have had many instances in which I have come across different methods of passing data between forms. I work on a large codebase -- some of these methods were written by others, which I subsequently extended, and others were written by myself. It seems there are two main paradigms, both of which I have coded rather comfortably.
1.) Pass the parent form to the child when instantiating or showing the child form. For example:
ChildForm.Instance = new ChildForm(this);
--Or--
ChildForm.Instance = new ChildForm();
ChildForm.Instance.Show(this.TopLevelControl);
This allows the child to pull information from the parent, as well as allows the parent to call methods on the child. Bear with me for a moment -- I do realize that this breaks so many paradigms, and is "bad" practice -- remember, I'm encountering much of this during maintenance of a larger codebase to which I am required to make incremental adjustments without doing a complete refactoring.
2.) Use an event delegate to allow for data to be transferred between parent and child forms. To the best of my knowledge, this still requires that the parent form establish this event when spawning the child. For example:
Within parent:
childForm = new ChildForm(this);
DataRead += new DataReadEventHandler(childForm.ChildForm_DataRead);
Within child:
public void ChildForm_DataRead(Data data)
{
if (InvokeRequired)
{
Invoke(new MethodInvoker(delegate() { ChildForm_DataRead(data); }));
}
else
//do something
}
Something of this nature. Now, I'm still not a strong coder in C# WinForms, but I do realize that the event/messaging approach is probably "better" from a design perspective.
Now, here is my question.
I have a main form, for naming's sake: ParentForm. ParentForm currently utilizes the latter form (har har!) of messaging to pass data to, let's say, FirstChildForm. Essentially, once ParentForm acquires data, it triggers the DataReadEventHandler, and data is passed from ParentForm to FirstChildForm.
No problem.
Now, I /also/ have a form spawned from ParentForm, called SecondChildForm. NB: this is not another instance of ChildForm... it's an entirely different form. Here's the catch -- when data updates on SecondChildForm, I want to have this data passed to FirstChildForm. It seems like such a simple idea, although I'm having some difficulty wrapping my head around how to implement it. All I can think of is setting up unique event handlers from ParentForm for each child, and having the event handler from SecondChildFrom then trigger ParentForm's event handler for FirstChildForm... this sounds terribly convoluted, as the data (of non-trivial size, I might add), must be first passed from SecondChildForm to ParentForm, and subsequently from ParentForm to FirstChildForm.
Is there a better way of doing this?
Also, I'd really prefer not to say this, but, to be perfectly honest, in this highly closed application, I'm OK with breaking paradigm for simplicity if the proper method is highly convoluted (would nevertheless allocate time in the future for proper refactoring -- yes, I actually /am/ able to do this!).
Cheers!
-Kadaj
So the data is first generated on the second child, so on that form we'll want an event that can be triggered that can provide that data:
public class SecondChildForm : Form
{
public event Action<MyData> SomethingHappened;
//Other code, including code that fires the event at some point
}
Then we have the first child which has some method that needs to be called passing in that data:
public class FirstChildForm : Form
{
public void WhenSomethingHappens(MyData data)
{
//Do stuff with data
}
}
Finally we have the main form that creates both of the forms and wires up the appropriate event handlers:
public class ParentForm : Form
{
public ParentForm()
{
FirstChildForm firstChild = new FirstChildForm();
SecondChildForm secondChild = new SecondChildForm();
secondChild.SomethingHappened += firstChild.WhenSomethingHappens;
//show forms and do other stuff
}
}
Voila.
Note that using this pattern each child doesn't know anything about their parent. They expose information needed by the parent through events, and they allow the parent to affect it through public methods, but they don't know or care which class(es) are using them. The parent does know about it's child type; it's appropriate for it to have an instance of the specific child type and to manipulate it's public members (but not its inner controls, which shouldn't be public) directly.
Related
I have a form and a logic class. Based on user actions, the class generates a list of actions. These actions then need to be displayed as buttons on the form, so the user can select from them.
My initial solution was this:
public class Logic {
public List<string> GetActions() {
List<string> result = new List<string>();
// ...prepare list
return result;
}
}
public class FrmGUI : Form {
Logic logic = new Logic();
private void PopulateButtons() {
foreach(string action in logic.GetActions(){
//...create button
}
}
}
The GUI retrieves the list of strings from the Logic class and then uses that to populate a panel with buttons. Now supposedly this is bad OO practise because I'm exposing something about how Logic class behaves. There is an assumption here that the GetActions method will always exist and that the Logic class will always be able to return this list of strings.
Another solution is this:
public class Logic {
public void PopulateButtons(Panel panel, Action<object, EventArgs> eventHandler) {
// ...prepare list
// ...populate buttons
}
}
public class FrmGUI : Form {
Logic logic = new Logic();
private void PopulateButtons() {
logic.PopulateButtons(this.panel1, actionButtonClickHandler);
}
}
Now here the GUI class knows nothing about the logic class and only expects to get the buttons populated. On the other hand, the logic class is now involved in GUI stuff.
What is the correct way to handle such cases. Or is there a third implementation which is better.
I'd use the former patttern: The Logic-layer creates information, and UI-layer uses that information to create the UI.
That way, if you decide to re-skin the UI to use a drop-down list of items you only have to change the UI layer, not the logic.
It means that the UI layer has a minimal dependency on the types/data provided by the logic layer (as long as it doesn't know anything about how the logic is implemented, that is fine), but the logic layer has no idea whatsoever about what the UI implementation is - which is what you want (the lower level components in a system should not know anything about the higher level design, while the higher level components must necessarily have a basic understanding of the low-level components that they utilise).
It would be preferable that the application (or some other external entity) creates both the Logic and UI and links them together, rather than the UI itself creating the Logic - this will help the UI and logic to be much more loosely coupled.
I would recommend placing a layer of abstraction between your Logic and your FrmGUI.
For a simplistic example, let's say you have a login in you application. Define an interface for your logical screen. Note there is no mention here of what controls are used. The Logic classes never knows the UI class/form used.
interface ILoginScreen : IScreen
{
event EventHandler LoginInvoked;
event EventHandler CancelInvoked;
string User { get; set; }
string Password { get; set; }
}
In your LoginLogic class you have code like this:
void Start() // initial LoginLogic method
{
ILoginScreen loginScreen = uiFactory.CreateLoginScreen();
loginScreen.User = string.empty;
loginScreen.Password = string.empty;
loginScreen.LoginInvoked += new EventHandler(LoginScreen_LoginInvoked);
loginScreen.CancelInvoked += new EventHandler(LoginScreen_CancelInvoked);
loginScreen.Show();
}
void LoginScreen_LoginInvoked(s, e)
{
if (ValidateCredentials(loginScreen.User, loginScreen.Password))
{
// goto the next screen logic controller
}
}
In your form, you implement ILoginScreen and refresh the UI fields with data from teh USer and Password properties. Additionally, you raise the required Login and Cancel events based on the user feedback (button click, Escape keystroke, whatever).
While this is a simplistic example, I do a lot of Windows Mobile and Windows CE apps where it is very common to want to run the same application on vastly different form-factors OS variants and this approach lets you literally snap on new GUI form-factors. The heart of that usage is the UIFactory that is dynamically loaded to provide the appropriate UI implementation.
That Logic can report the actions it supports (1st pattern) looks fine to me (but the return type of GetActions really should be IEnumerable<string> instead of a list).
Not so good is that in your sample the form instantiates the Logic class directly. Typically, you'd create an interface or abstract base class for the different types of Logic classes that you might have, and have concrete implementations fill in the functionality. The form would then get the logic to use through some inversion-of-control mechanism.
correct????? Over the years lots of people have invested lots of time in trying standardise this approach and I'm afraid the answer may be deduced from the number of ui design patterns out there!
You may want to look at MVC, MVP, MVVM patterns, all of which are in vogue at the moment.
In general:
it is a good idea to try to split logic from presentation, so you're on the right lines. But remember that one of the consequences of this split is that it is better for your "logic" not to know anything about presentation (since you already have a class responsible for that).
So you might want to think about the concept of "buttons", and think (from your logic point of view), "don't I really mean commands?". They only really become buttons when you think of them in the context of a screen. But, say, a command to load the transactions on a particular bank account....you don't need a screen to conceptualise how this would work.
A good thing I find is to imagine that you're going to develop this app with both a forms front end and, say, a web front end which does exactly the same thing. Obviously these two apps would have a totally different presentation layer because of the fundamentally different technologies involved.
But because you don't want to write code twice you'll have a "logic" layer too, where you'll stuff as much common code as you can. For example, deciding whether a bank account is overdrawn - doesn't matter whether you're web or win, overdrawn is still overdrawn. And conversely, any place where you'd end up writing different code between web and win belongs into your "presentation" layer. For example, displaying an overdrawn balance in red.
Food for thought.
the first one is better, because your interface between GUI and logic is just a list of string.
After, it all depends on the way you're calling actions on your logic class from your button.
If you have a generic method taking the action string, it's fine. If you need to call different methods on your logic class depending on the action string, you'll need a mapping in the GUI class to map action string and method call. you could also import this "action string - mapping method" from your logic class to keep things separated.
My opinion is, it depends on the reason for creating something like a logic tier and a GUI tier. I think the most common reason is to reuse the logic, e.g. to use it for a WPF and a web GUI, or the data has to be processed before sending it to the GUI. Your first example fits the mentioned pattern. In your second example the logic seems not to be reuseable, because its gui specific.
However, in the real world there it right or wrong answer. The architecture should fit your needs and make your project maintainable(e.g. by reduce redundant code).
In your case the question is: How often do you need these functions and where/when do you need them?
I am building an WinForms application with a UI that only consists of a NotifyIcon and its dynamically populated ContextMenuStrip. There is a MainForm to hold the application together, but that is never visible.
I set out to build this as SOLIDly as possible (using Autofac to handle the object graph) and am quite pleased with my success, mostly getting along pretty well even with the O part. With the extension I am currently implementing it seems I have discovered a flaw in my design and need to remodel a bit; I think know the way I need to go but am a bit unclear as to how to exactly define the dependencies.
As mentioned above, the menu is in part populated dynamically after starting the application. For this purpose, I defined an IToolStripPopulator interface:
public interface IToolStripPopulator
{
System.Windows.Forms.ToolStrip PopulateToolStrip(System.Windows.Forms.ToolStrip toolstrip, EventHandler itemclick);
}
An implementation of this is injected into the MainForm, and the Load() method calls PopulateToolStrip() with the ContextMenuStrip and a handler defined in the form. The populator's dependencies are only related to obtaining the data to use for the menu items.
This abstraction has worked nicely through a few evolutionary steps but isn't sufficient anymore when I need more than one event handler, e.g. because I am creating several different groups of menu items - still hidden behind a single IToolStripPopulator interface because the form shouldn't be concerned with that at all.
As I said, I think I know what the general structure should be like - I renamed the IToolStripPopulator interface to something more specific* and created a new one whose PopulateToolStrip() method does not take an EventHandler parameter, which is instead injected into the object (also allowing for much more flexibility regarding the number of handlers required by an implementation etc.). This way my "foremost" IToolStripPopulator can very easily be an adapter for any number of specific ones.
Now what I am unclear on is the way I should resolve the EventHandler dependencies. I think the handlers should all be defined in the MainForm, because that has all the other dependencies needed to properly react to the menu events, and it also "owns" the menu. That would mean my dependencies for IToolStripPopulator objects eventually injected into the MainForm would need to take dependencies on the MainForm object itself using Lazy<T>.
My first thought was defining an IClickHandlerSource interface:
public interface IClickHandlerSource
{
EventHandler GetClickHandler();
}
This was implemented by my MainForm, and my specific IToolStripPopulator implementation took a dependency on Lazy<IClickHandlerSource>. While this works, it is inflexible. I would either have to define separate interfaces for a potentially growing number of handlers (severely violating OCP with the MainForm class) or continuously extend IClickHandlerSource (primarily violating ISP).
Directly taking dependencies on the event handlers looks like a nice idea on the consumers' side, but individually wiring up the constructors via properties of lazy instance (or the like) seems pretty messy - if possible at all.
My best bet currently seems to be this:
public interface IEventHandlerSource
{
EventHandler Get(EventHandlerType type);
}
The interface would still be implemented by MainForm and injected as a lazy singleton, and EventHandlerType would be a custom enum with the different types I need. This would still not be very OCP compliant, but reasonably flexible. EventHandlerType would obviously have a change for each new type of event handler, as would the resolution logic in MainForm, in addition to the new event handler itself and the (probably) newly written additional implementation of IToolStripPopulator.
Or.... a separate implementation of IEventHandlerSource that (as the only object) takes a dependency on Lazy<MainForm> and resolves the EventHandlerType options to the specific handlers defined in MainForm?
I'm trying to think of a way of actually getting the event handlers out of MainForm in a feasible way, but can't quite seem to right now.
What is my best option here, providing the loosest coupling and most elegant resolution of the different event handlers?
[*Yes, I probably should have left the name alone to really comply with OCP, but it looked better that way.]
What is my best option here, providing the loosest coupling and most
elegant resolution of the different event handlers?
Common solution are not exist and it depends on the global application architecture.
If you want a loosest coupling, EventAggregator pattern can help you in such case (your IEventHandlerSource similar to that):
Pattern Description - http://martinfowler.com/eaaDev/EventAggregator.html
Implementation in Prism - http://msdn.microsoft.com/en-us/library/ff921122.aspx
But, global events should be used with great caution - they can smudge architecture, because subscribe to the event will be possible anywhere.
Important thing in DI and IoC: lower dependency should not to know about higher dependency.
I think, and as Leon said earlier, will be better to create some interface like ITool<T> and store list of tools in the MainForm. After some action MainForm will invoke certain methods in this tools.
Firstly, I think you shouldn't claim your mainform must contain all event handlers. You clearly ran into the fact that there are different handlers with different needs (and probably different dependencies), so why should they all be fitted into the same class?
You can probably take some inspiration from the way events are handled in other languages. WPF uses Commands, Java has Listeners. Both are objects, not just a delegate, making them easier to deal with in an IOC scenario. It's fairly easy to simulate something like that. You could abuse the tag on your toolbar items, like this: Binding to commands in WinForms or use lambda expressions inside PopulateToolbar (see Is there anything wrong with using lambda for winforms event?) to associate the toolbar item with the correct command. That's assuming that since PopulateToolbar knows which items need to be created it also know which action/command belongs to each item.
The object representing the action can have their own dependencies injected, independently of the main form or other actions. Toolbar items with their own actions can then be added or removed later without affecting your main form or any of the other actions, each action can independently be tested and refactored.
Bottom line, stop thinking about EventHandlers, start thinking about Actions/Commands as an entity in their own right and it will become easier to come up with a suitable pattern. Make sure you understand the Command Pattern, because that's pretty much what you need here.
Have you tried to use an event aggregator? See: Caliburn framework, event Aggregator
An event aggregator will decouple the toolstrip from you main form.
public interface IToolStripPopulator
{
ToolStrip PopulateToolStrip(ToolStrip toolstrip);
}
Wrap the aggregator for convenience like this:
public static class Event
{
private static readonly IEventAggregator aggregator = new EventAggregator();
public static IEventAggregator Aggregator
{
get
{
return aggregator;
}
}
}
You define one or more event classes, for example:
public class EventToolStripClick {
public object Sender {get;set;}
public EventArgs Args {get;set;}
}
In the controller that creates the toolstrip, publish the custom event in the Click handler write:
public void ControllerToolStripClick(object sender, EventArgs args )
{
Event.Aggregator.Publish(new EventToolStripClick(){Sender=sender,Args=args)});
}
In the mainForm implement the interface IHandle
public class MainForm : Form, IHandle<EventToolStripClick>
{
...
public void Handle(EventToolStripClick evt)
{
//your implementation here
}
}
If you are hosting child components within your form, and they can populate the main application "shell".
You could have a base class ShellComponent, that inherits from System.Windows.Forms.ContainerControl. This will give you a design surface as well. Instead of relying IToolStripPopulator, you could have ITool like such.
public inteface ITool<T>
{
int ToolIndex { get; }
string Category { get; }
Action OnClick(T eventArgs);
}
In ShellComponent you could call, public List<ITool> OnAddTools(ToolStrip toolStrip) from the MainForm each time a view is loaded. This way the component would be responsible for populating the toolstrip.
The 'ShellComponent' would then ask the IoC container for handlers that implement ITool<T>. This way your ITool<T> provides a way to separate the event (in the MainForm, or the ContainerControl) and push this out to any class. It also allows you to define exactly what you want to pass through for arguments (as opposed to MouseClickEventArgs ect).
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.
When I need to pass some information from a form to another I usually do the following:
Form2 form = new Form2(this);
form.ShowDialog();
And inside Form2.cs, I use a constructor like:
private Form1 parent;
public Form2(Form1 form)
{
...
parent = form;
}
This way I can get a information from a textbox doing parent.textbox1.Text only if textbox1 is not a private member from Form1. Ok, a lot of time I need to get information about controls in Form1, should I make the setters and getters for each attribute of a control needed in Form2? For example: I need to know the values of Text, ReadOnly and Location. Should I make the setters and getters for each one of these attributes? Is the use of internal modifier a bad practice?
The correct way to do it is with delegates. They are really pretty simple but it takes awhile to get your head around them. Here is a great example of what I think you're looking for: http://samgaut.blogspot.com/2007/11/use-delegates-to-pass-data-between.html
Since I am not allowed to add comments to answers I'm going to add this.
The linked blog post from the accepted answer does not make sense to me (could just be my lack of thorough understanding of delegates).
If the next-in-line form frmDestination has a publicly accessible setter method (SetCustomerID(string strCustID)), then why do you need to pass that into a delegate when you can just pass customerID directly to the setter?
I noticed he mentioned that
Basically, the member variable that is set within the delegate method will be populated before the Form_Load event is executed. If you notice the delegate call is executed before the frmDestination.Show() call is made. This way, you have that variable available to execute in your Form_Load processing.
Would just calling dest.SetCustomerID(customerID) before dest.Show() not do the same thing?
Seeing as this is not a reusable framework from what I can tell, I wouldn't create wrapper properties around the control properties.
If there was something that needed to be flexible about this parent form then the proper course might be to use an interface that specifies the particular controls exist or a specific base form class.
what is the best way to keep a child control up to date for changes in the parent.
I have a number of child controls hosted inside my parent object and I can think of two ways to send change information to them.
1) wire the child control to an event in the parent and fire that event on a change in the parent
2) keep a list of the children in an array and iterate through the array when the change has happened and invoke a method in the child to handle the new changes.
I hope I describe it okay.
Both work but there is probably a right way to handle this and a wrong way.
EDIT:
below is my code...for event method. I am not happy with how I have wired the child to the parent;any sugestions.
The Parent...
public class A_Parent
{
public delegate void DelUpdateMessage( string msg );
public event DelUpdateMessage UpdateMessage;
public A_Parent()
{
a_Child1.prnt = this;
a_Child2.prnt = this;
a_Child3.prnt = this;
a_Child4.prnt = this;
}
private void FireUpdateMessageEvent( string message)
{
var handlers = UpdateMessage;
if (handlers != null)
handlers( message );
}
}
The child...
public class A_Child
{
A_Parent pnt;
public A_Parent prnt
{
set
{
pnt = value;
pnt.UpdateMessage += new A_Parent.DelUpdateMessage(pnt_UpdateMessage);
}
}
void pnt_UpdateMessage(string msg) { }
}
Your #1 solution is the best bet, as it allows you to change around your implementation without a change in the parent. Since the parent arguably doesn't care if it has children, the event-based approach is ideal.
UPDATE
The reverse-event approach is disingenuous. People are stating that the parents clearly know what children are interested in them, and I simply tend to disagree with that statement. My designs usually have the children dynamically interested in the parent, and the children subscribing to the events is generally the most favorable way of doing so.
You can find such examples in the .NET model, such as the Page which has events that you can tie into.
Events are not the proper choice here. The parent never has a problem figuring out what child controls need to be notified. Simply add a public method to the UC, like UpdateMessage(). The parent can directly call them.
Reserve events for being able to notify listeners when you have no idea what listeners might be interested. Having a "reverse event" like you're contemplating is unhealthy, it keeps a reference on the form. A form should never be referenced so that it can get garbage collected when it closes. That isn't a real problem here, since the reference is held by a child control, but the principle holds.
Event mechanism is a common routine for such tasks. It will be much more flexible than your second solution.