Passing values between three forms in C# .NET - c#

I have a windows application which has three forms : Form1,2,3.
--Form 1, has two buttons , openform2, openform3.
--Form2 has a textbox form2_textbox,and button form2_button
--Form3 has a textbox form3_textbox
now, on clicking button openform2 on form1, Form2 opens, a string is entered in textbox form2_textbox of Form2, now when bu tton form2_button of this form is clicked, then i want that Form1 receives this string value & stores it in a string receivefromform2,
and then displays this string value on to form3_textbox of Form3.
please guide me how to do this task?

Ignore the fact that they're forms. Think of them as any other objects - you'd use properties, methods, events and constructors. GUI controls have a few oddities around them, mostly in terms of thread affinity, but usually you should apply the same object oriented approaches to them as you would anything else.
For example, when constructing Form2 in Form1, add an event handler to the button in Form2 (either by creating a new event in Form2 or exposing the button via a property and attaching it directly). The event handler would ask Form2 for the text in the textbox, and use that when creating Form3.

There are a couple of ways to do this. Using .NET events is one but requires pretty coupled wiring.
What I would suggest (and this is how I do this) is to use your own bus (observer pattern). Let's call it MessageBus. All your forms could use the same instance of this bus and when something interesting happens you could publish some Message. I would keep it strongly typed but for the sake of simplicity let's say this:
public class Message<T>
{
public string Name { get; set; }
public T Data { get; set; }
}
You would then have subscribers on your bus that respond to messages that they are interested in.
public class MessageBus
{
public void Subscriber(ISubscriber subsriber)
{
// register your subscriber in some list
}
public void Publish(Message message)
{
// loop through subscribers and let them know
// e.g. subscriber.Handle(message);
}
}
So to wire all this up each form that would like to publish an event (such as your form2) would need a reference to the message bus and each object that is interested in receiving events (such as form3) would register as a subscriber.
The only difference between this an using .NET events is that the various publishers and subscribers do not need to know about each other so they are loosely coupled --- they only need to know about the bus. It is possible to get the same loose coupling using .NET events but that takes a lot of fancy footwork.
More than one way to skin a cat I suppose.
I have a more mature implementation of this in my composite ui framework I use for the tooling on our FOSS service bus. You can take a look if you are interested:
Shuttle Service Bus on CodePlex
If you download the source you will find it in the Shuttle.Core.UI project.
Hope it makes sense.

Related

Is it a bad idea to give a C# form a static property pointing to the only instance of the same form?

I have a fairly simple application that monitors folder activity and logs it on a server.
In this application I start off with a Form object called Form1. On this form I have a NotifyIcon. Because I need to change the text in the BalloonTip of the NotifyIcon from different Forms along the way, I was thinking of setting a static property of Form1 that will point to the only instance of Form1. This is how it would look in my oppinion:
public partial class Form1 : Form
{
private static Form1 staticRef;
// Other private properties
public Form1()
{
InitializeComponent();
staticRef = this;
// Rest of constructor logic
}
public static void changeNotifyBalloonText(String newText, int timeInMillis)
{
if (staticRef != null && staticRef.notifyIcon1 != null)
{
staticRef.notifyIcon1.BalloonTipText = newText;
staticRef.notifyIcon1.ShowBalloonTip(timeInMillis);
}
}
// Rest of public and private methods
}
Other things to be noted:
a. There will never be more than 1 instance of Form1.
b. I always check the value of staticRef against null, before trying to use it.
c. I cannot afford to make a temporary, local instance of Form1 just to set a BalloonTip message.
d. This solution works very well, i'm more interested in knowing if it's "too hacky" and if so - what would be a better approach to my issue?
e. The closest thing I've found that may answer my question (about static properties) to some degree is here:
Is using a static property in a form bad practice knowing that there's only only one instance of the form?
What you have here is a form of the singleton pattern.
The singleton pattern certainly has its detractors and its defenders (google "singleton anti-pattern").
It is though a very convenient way of doing this.
I would recommend an approach like either::
Create a class that represents operations on a notify icon.
Have that class as the only class that accesses staticRef.notifyIcon1.
Have it do so as a reference to notifyIcon1, not as Form1.
Have a static method or property that gets the icon-controlling class.
Or:
Simply have a static method or property that returns the NotifyIcon object.
Make it the only method that accesses the static reference to the form.
The advantage of one over the other is around whether you want to expose the full interface of NotifyIcon or provide a set of operations that make sense to your application.
This way you are still using the singleton pattern, but in restricting the way that it is accessed the fact that there is global state has less of a global impact, relates more directly to the purpose of that global state (the icon itself), and is more readily extended to different uses. e.g. if you some day need to have two icons, you change the method that static method or property to one that does a lookup of some sort, and change all the current calls to use the key for the first icon. Meanwhile, implementation changes up to and including completely changing which form provides that icon can be done quickly in one place.
I think your current design is tightly coupled to other classes sending the notification and it requires your form to be a single instance as well.
You can decouple this a great deal by using an event broker to send the notification to any interested parties. Many frameworks have event brokers, I have used one from Prism but there are others as well.
Your code will then only know about the event broker and what events your class is interested in.
public partial class Form1 : Form
{
private static IEventBroker eventBroker;
// Other private properties
public Form1(IEventBroker eventBroker)
{
InitializeComponent();
this.eventBroker = eventBroker;
this.eventBroker.Register<NotifyBaloonText>(changeNotifyBalloonText);
}
public static void changeNotifyBalloonText(NotifyBaloonText args)
{
notifyIcon1.BalloonTipText = args.NewText;
notifyIcon1.ShowBalloonTip(args.TimeInMillis);
}
// Rest of public and private methods
}

How to communicate between different winforms

I have a container WinForm called frmMain which holds another forms like frmOrder, frmMessage, the subforms was added in a TabPage control.
What I want to do is communicating between subforms, say user changes something in frmOrder and frmMessage need to be notified, currently I think the communication need to be delegated through the frmMain.
One solution I can think is to make subforms deriving from my custom Form derived class which defines interface say:
public class MessageEnabledForm: Form
{
public void SendMessage(String destFormName, String messageType, String data);
public void ReceiveMessage(String destFormName, String messageType, String data);
}
I don't know whether this is feasible, and is there any other solutions I can employ? which is generic and needn't to know the concrete subform.
Based on your question, I don't think inheritance is the best tool for the job. I say its not the best choice because you are not dealing with an "is a" relationship. I think you should consider using Events and Delegates to handle the communication between forms and subforms. The following MSDN article provides a good overview of Handling and Raising Events. You also may want to refresh yourself on the .NET INotifyPropertyChanged Interface if you using data binding in the subforms.
You could use an Interface like this, that all the child forms implement:
public interface Communication
{
public delegate void SendMessageDelegate(String destFormName, String messageType, String data);
public event SendMessageDelegate SendMessage;
public void ReceiveMessage(String destFormName, String messageType, String data);
}
When the main form receives the event, it can iterate over its "child" forms looking for a match on destFormName then call its ReceiveMessage() implementation (after casting it to the Communication interface).

Mixing enums with event classes in an event aggregator

I attempted to implement my own simple event aggregator recently. I got a lot of inspiration from the event aggregator article on MSDN. There is one thing that I notice about the event aggregator on MSDN is the events are actually classes on their own. This isn't really a bad thing at all. However, I just find it awkward to always create a new empty class for every single little event.
The reason I find it awkward is because of the need to create a class for every single granular event. A mouse click event, for instance, would have double_click, single_click, left_click, right_click, etc. And all of these are going to have a class of its own. It gets messy after a while.
So in my own implementation, I thought I could make it in such a way where the ClickEvent is a class, but all the granular events related to the Click event would then be "types" of the ClickEvent. In this case, the "types" are enum. The usage would look something like this:
//Publisher
eventAggregator.GetEvent<ClickEvent>.Publish(ClickEventType.Double_Click, eventArgs);
//Subscriber
eventAggregator.GetEvent<ClickEvent>.Subscribe(ClickEventType.Double_Click, handlerMethod);
However, I'm not sure if this implementation defeats the whole purpose of having a strongly typed event? Now, it seems like the ClickEvent is merely a container for the different event enum types.
Yes it does (seem like a container that is) - your handler will fire regardless of the click type and there will be some code required in the handler to determine the type of click, which makes things a little messier.
If your issue is mostly the organisation of the files/classes and keeping the code tidy, why not just create the click events as nested classes within a main click class
e.g.
public static class ClickEvents // Prevent instantiation
{
public class SingleLeft { }
public class SingleRight { }
public class DoubleLeft { }
public class DoubleRight { }
// Are there any more click events possible?!
}
eventAggregator.GetEvent<ClickEvents.SingleLeft>.Publish();
Aside from that, it's the uniqueness of the type that determines the event signature, and therefore multiple types are required to satisfy this particular implementation
At least the above keeps your handler code clean
void HandleLeftClick()
{
}
vs
void HandleClick(ClickArgs e)
{
if(e.ClickType == ClickType.Left)
{
}
}
Edit:
Also remember that you can subscribe multiple events to the same handler if you want to handle more than one click type:
eventAggregator.GetEvent<ClickEvents.SingleLeft>.Subscribe(HandlerMethod);
eventAggregator.GetEvent<ClickEvents.SingleRight>.Subscribe(HandlerMethod);
(this would work in the rare situation that the subscriber didn't care which mouse button was clicked)
I think you missed one possibility. You see, you don't have to create a new class for each notification. Instead, you are free to reuse classes but carry some additional state of arbitrary complexity inside.
public class MouseClickNotification {
public bool IsDoubleClick;
public MouseButton ClickedButton;
// any additional stuff
This way it is you who precisely define the granularity of your notification model.

Why to use events somewhere where method is enough?

I read some events tutorial and just do not get what is the benefit in simple code like this..method should be used the same way:
class Bulb
{ public delegate void handler();
public event handler Glowing;
...
Glowing+=SomeMethod;
private void TurnOn
{
Glowing();
}
private void SomeMethod
{
}
}
Simply Events allow others using your code to perform some custom Implementation they want when that Event occurs (when Bulb is Glowing).
Simply calling your method won't tell anybody that something has happened.
Events are very basic Element of any Event Driven Programming
If your program doesn't need to tell about an event you don't need to implement such Functionality. However having such functionality has benefits.
For Example when using a List Class you dont know when an Item got added to it (if at some point some other code does that) but in a ObservableCollection you get notifications when Items are Added or Removed.
An event is a message sent by an object to signal the occurrence of an action. The action could be caused by user interaction, such as a mouse click, or it could be triggered by some other program logic.
The idea is that a different class which can hold Three different Bulbs can get notified by the event (if it implements a handler) that the light has been turned on and is Glowing.
So the benefit does not reside in the simply class but in what ever classes/objects are going to be holding/using instances of the Bulb class.
Hope that made some sense :)
Events over methods become handy when you have a class dependency that needs to know or be notified about a stateful change:
public class Lamp
{
Bulb inThelamp = new Bulb();
inTheLamp.Glowing += myLampMethod;
// If these arguments have been defined for this event that is
public void myLampMethod(object sender, EventArgs e)
{
// Code to react to the light suddenly being on
}
}
This allows the Lamp class to recognize that something has turned the bulb on. In many cases it will be through some action in the Lamp (click, pushknob, etc). But in some cases it could be an external class that calls a public Bulb property directly without using the Lamp itself (such is if(PowerCompany.BillsPaid) Lamp.BulbInTheLamp.TurnedOn();). This is all assuming that the modifiers are set to allow this kind of access.
The point is that it allows notification of an occurrence rather than requiring that a particular method be called manually each time you want an action to occur.

Interactions between windows

what's the best/proper way of interacting between several windows in C# app?
Recently, I've run into a problem where one of program windows has to call method modifying main window. My solution was to create factory-like class, that would arrange all underlying model-data and organize the communication between various windows (through delegates). However, as passing one or two delegates was not a problem, I started thinking what if my other windows would need 10 delegates to interact properly with main window? Are delegates good solution? How to pass them in good way - through constructor, properties? Or maybe the need of using that many delegates is some serious design flaw itself?
You need to split the Model from the view by a Controller. Put an object that will be able to have both form reference and that will be able to manage the shared information.
An other solution is to send the reference of the formX to the formY this way they can communicate.
We use a custom built forms manager that uses the subject/observer pattern.
Every form that is opended is reported to the FormsManager, the FromsManager makes itself an observer of the form.
It also makes the form an observer of the FormsManager.
So you end up with every form observing the FormsManager and the FormsManager observing every form. Each form can then communicate to any other form via the FormsManager without each form having to be aware of all the others.
If it's only needing to interact with the main window, why not give a reference to the main window in the constructor of the others?
public class MainForm : Form
{
}
public class OtherForm : Form
{
protected MainForm MainForm { get; set; }
public OtherForm(MainForm mainForm) : base()
{
this.MainForm = mainForm;
}
}
EDIT:
Simple and effective.
If your forms need to interact with all the other forms of the application, then a service locator type pattern might be better suited.
Previously with MFC, there was something that notify all windows. You will pass an event id with a parameter.
You could do something similar with one delegate that will expose an event id and a collection of parameter.
The greatest advantage of this is that windows only have to implement one gateway.
You can use a single delegate, using a custom EventArgs to pass several informations, like: type of notificaton, additional parameters, etc.

Categories