Getting events to work on a common data object in C# - c#

I'm having a bit of a problem with implementing an event architecture in C#. The basic layout is like this:
We have a network-layer(dll) that communicates with a server. This layer has made several interfaces for events of changes within the database. A database-field changes and the dll calls my implementation of the appropriate interface. I have a GUI, and within it's main method a data-object, which stores lists of temporary data I display until something gets changed by my user, in which case I'll send the changes to the database.
The problem is now that I can't implement an event-handler within the network-layer, or my implementation of it's interfaces, because my data-object(which should get the results of the events) only exists within my GUI, and it's main method, and as such is not known to the appropriate objects.
I'll make an example as pseudo-code:
namespace ClientConnection
{
public class DataListener : IDataListener
{
public delegate void SomethingReceivedHandler(object sender, SomethingData packet);
public event SomethingReceivedHandler somethingRecievedHandler;
public void SomethingReceived(SomethingData packet)
{
if (SomethingRecievedHandler != null)
{
SomethingRecievedHandler(this, packet);
}
}
Is my current implementation of the interface. The Layer has something akin to:
private void ProcessPacket(SomethingData packet)
{
if (packet == null)
return;
try
{
if (packet is SomethingData)
DataListener.SomethingReceived(packet as SomethingData);
//snip
And my main-method is:
public partial class Main : FormMain
{
Data ClientData; //Contains all temporary data within the GUI
public frmMain()
{
ClientData = new Data();
DataListener dataListener = newDataListener();
InitializeComponent();
}
And if the event fires I want to do something like:
ClientData.SomeList.Add(packet)
depending on the context.

The problem is now that I can't implement an event-handler within the network-layer, or my implementation of it's interfaces, because my data-object(which should get the results of the events) only exists within my GUI, and it's main method, and as such is not known to the appropriate objects.
Not sure I see the problem. The publisher of the event doesn't need to know anything about the subscriber of the event - that's what makes them useful.
Based on your pseudo-code, it should be as simple as:
public partial class Main : FormMain
{
Data ClientData; //Contains all temporary data within the GUI
public frmMain()
{
ClientData = new Data();
DataListener dataListener = new DataListener();
// Add an event handler
dataListener.somethingReceivedHandler +=
(object sender, SomethingData packet)
{
if (someContext) ClientData.SomeList.Add(packet);
};
InitializeComponent();
}
You probably want to elevate dataListener to a field (instead of a local) so that it stays alive outside of the ctor (and you can unsubscribe when your form closes).

Related

Getting a class to 'inform' another class that it needs to change (Events?)

Okay, I've been searching on the site and Google and can't quite get my head around where things need to be in terms of delegates and eventhandlers and the like so hopefully someone here can help/explain what I need to do.
So, I am writing a simple database application (using SQLite). There is a mainform that is the MDI parent (that's basically a big window with menus at the top). The menus launch other windows that allow view, edit and insert into various tables of the database.
One of those windows is a LOG window which shows my log table.
At the moment, if a user changes something in the window showing the data in TABLE. The operation also writes into the log table. If the Log window is open, however, the log view doesn't update.
So, I've figured out I probably need to 'fire' an event from my TABLE UPDATE code that my LOG window 'subscribes' to (so it can update the DataGridView).
What I can't figure out is where the different 'bits' of the event go.
Should the MdiParent have the public delegate void EventHandler();? If not where?
which class gets the public static event EventHandler logGoneStale;?
The only bit I'm reasonably sure about is that the Window that displays the log (which has a method called public void UpdateLogDataGridView() - which calls the database object/methods to (re-)populate the datagridview) needs to have:
something like logGoneStale += new EventHandler(UpdateLogDataGridView); in it. Is that at least right?
Totally befuddled - it seems none of the event examples/tutorials on MSDN are trying to do what I want to achieve.
You need to define an event in the class that is sending the event, and append an event handler in the class that should receive the event. To make things slightly easier, starting with C# 3.5 you can forget about the delegate keyword altogether and use a lamba expression as event handler. Also note that it in most cases it makes no sense to make an event static, since usually events are fired by an instance, not by a class.
Example:
class SendsEvent
{
public event EventHandler MyEvent;
public void FireEvent()
{
if(MyEvent != null) // MyEvent is null if no handlers have been attached
{
MyEvent(this, new EventArgs()); // event fired here
}
}
}
class ReceivesEvent
{
private SendsEvent eventSource;
public ReceivesEvent(SendsEvent eventSource)
{
this.eventSource = eventSource;
// Attach event handler - can be a lambda expression
// or method with signature
// "void HandleEvent(object sender, EventArgs e)"
this.eventSource.MyEvent += (sender, args) =>
{
// do something when event was fired
Console.Out.WriteLine("Hello. Event was fired.");
};
}
}
class Program
{
public static void Main()
{
var eventSource = new SendsEvent();
var eventReceiver = new ReceivesEvent(eventSource);
eventSource.FireEvent();
}
}
I hope this helps you.
Working with events requires you to have both an event publisher and an event subscriber.
#chris' answer is correct.
Besides, you need to raise the event on the closest point where the action for which you want to be notified takes place.
For example, implementing the INotifyPropertyChanged interface.
public class Customer : INotifyPropertyChanged {
public string Name { get; set; }
public string Address {
get { return address; }
set {
address = value;
if (thereArePropertyChangedEventSubcribers())
raisePropertyChangedEventFor("Address");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void raisePropertyChangedEventFor(string propertyName) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private bool thereArePropertyChangedEventSubcribers() {
return PropertyChanged != null;
}
private string address;
}
So here, the Customer class allows for the publishment of its change of address. So, whenever anyone is interested to be notified when the address has changed, it subscribes to the event like so:
Customer.PropertyChanged += new PropertyChangedEventHandler(customerPropertyChanged);
Or else like so:
Customer.PropertyChanged += customerPropertyChanged;
You might even have noticed that the closest point where the address has changed in directly after it has actually changed. The only requirement is that the method used as the event handler has the same signature as the event itself. If you take a look at the PropertyChangedEventHandler Delegate, one may notice that it signature awaits an object as the first parameter, that is, the object that fired the event, and a PropertyChangedEventArgs instance to notify about the property that has changed.
To come back to your example, you wish to be noticed whenever a log has been inserted into the underlying database so that a refresh of your Log window may occur. There are two questions that need to be answered whenever you want to use events.
What shall my publisher be?
What shall my subscriber be?
What shall my publisher be?
Should the MdiParent have the public delegate void EventHandler();?
Short answer: No!
If not where?
The event declaration best fits the publisher. Should you have a class responsible for logging, then this is where the public delegate void EventHandler(); should reside, as it is it that is responsible to raise the event whenever there are subscribers.
Whenever there is a successful Log inserted, it shall notify whatever subscriber interested to know about the new Log Entry.
public class Log {
public void UpdateLog(string description) {
// insert the new Log line into your database.
if (thereIsAtLeastOneNewLogEntryAddedSubscriber())
raiseTheNewLogEntryAddedEvent();
}
public event EventHandler NewLogEntryAdded;
private raiseTheNewLogEntryAddedEvent() {
NewLogEntryAdded(this, EventArgs.Empty);
}
private bool thereIsAtLeastOneNewLogEntryAddedSubscriber() {
return NewLogEntryAdded != null;
}
}
What shall my subscriber be?
This question can be answered through another question:
What do you need to do when the event fires?
In your case, you wish to update a Log window whenever it is opened.
The only bit I'm reasonably sure about is that the Window that displays the log (which has a method called public void UpdateLogDataGridView() - which calls the database object/methods to (re-)populate the datagridview) needs to have:
something like logGoneStale += new EventHandler(UpdateLogDataGridView); in it. Is that at least right?
Yes, you're right! =D
You actually subscribe to the event per this line. So, it tells the application that the window that displays the log is interested to know about log changes in your database.
public class WindowThatDisplaysTheLog : Form {
public WindowThatDisplaysTheLog() {
InitializeComponent();
log = new Log();
log.NewLogEntryAdded += UpdateLogDataGridView;
}
private void UpdateLogDataGridView(object sender, EventArgs e) {
// Reload your Log entries from the underlying database.
// You now shall see the LogDataGridView updating itself
// whenever a new log entry is inserted.
}
private Log log;
}

Event Handlers and Interfaces

I have an interface called IDataIO:
public interface IDataIO
{
event DataReceivedEvent DataReceived;
//.....more events,methods and properties
}
I also have multiple classes that implement this interface, namely UdpIO, TcpIO, SerialIO.
Now, I have an IO class that allows me to switch between different input/output hardware. Each instance of this class has a CurrentIODevice property, which could be one of SerialIO,UdpIO or TcpIO. When this property is assigned, i attach 1 or more handlers to the DataReceivedEvent so that my GUI is notified when incoming data is received, as well as other classes that need to be notified.
public class IO
{
IDataIO CurrentIODevice;
public IO()
{
SerialIO serial = new SerialIO();
TcpIO tcp = new TcpIO();
UdpIO udp = new UdpIO();
CurrentIODevice = serial;
}
}
I also have a IOManager class that holds multiple IO objects.
public class IOManager
{
List<IO> Ports = new List<IO>();
public IOManager()
{
Ports.Add(new IO());
Ports.Add(new IO());
}
Ports[0].CurrentIODevice = serial;
Ports[0].CurrentIODevice.DataReceivedHandler += MyGuiUpdate;
Ports[0].CurrentIODevice.DataReceivedHandler += MyDataProcessing;
}
My concern (its not an issue atm) is how I am going to change between different IDataIO interfaces at runtime.
What is the effect of, at runtime, performing the following statement:
//i know this is illegal but just to demonstrate
IOManager.Ports[0].CurrentIODevice = tcp;
Will the event handlers still be functioning (and correctly)?
Do i need to unassign the events before the CurrentIODevice is assigned, and then re-assign the handlers again after? If this is the case, I can see this approach getting quite messy, so if anyone has a better approach to this problem I'm all ears :)
No, your handlers will not work because they're attached to the old object. Interfaces provides...an interface to an object, see it as a kind of contract but they're not a different object themselves.
If you need to switch between different implementations of the interface (at run-time) and to keep all handlers working you have to have the same object reference for the interface itself, kind of strategy pattern (more or less).
In your case you may, for example, implement the IDataIO interface in a DataIO object. It'll expose a property (or a method, I think its intent is more clear) to switch between different implementations of that interface (serial, TCP or whatever). It'll be the only one object to attach an event handler to that interface (and it'll drop the handler when the concrete implementation will change). Users of that object will always see it, whatever it's the concrete implementation it's using.
Example
This is a small example to explain this concept. The generic interface is this:
interface IDataIO
{
void Write(byte[] data);
byte[] Read();
event EventHandler DataReceived;
}
This is the concrete implementation of IDataIO, other classes will use only this class directly:
sealed class DataIO : IDataIO
{
public void SetChannel(IDataIO concreteChannel)
{
if (_concreteChannel != null)
_concreteChannel.DataReceived -= OnDataReceived;
_concreteChannel = concreteChannel;
_concreteChannel.DataReceived += OnDataReceived;
}
public void Write(byte[] data)
{
_concreteChannel.Write(data);
}
public byte[] Read()
{
return _concreteChannel.Read();
}
public event EventHandler DataReceived;
private IDataIO _concreteChannel;
private void OnDataReceived(object sender, EventArgs e)
{
EventHandler dataReceived = DataReceived;
if (dataReceived != null)
dataReceived(this, e);
}
}
Finally some code for testing:
class Test
{
public Test()
{
_channel = new TcpIO();
_channel.DataReceived += OnDataReceived;
}
public void SetChannel(IDataIO channel)
{
_channel.SetChannel(channel);
// Nothing will change for this "user" of DataIO
// but now the channel used for transport will be
// the one defined here
}
private void OnDataReceived(object sender, EventArgs e)
{
// You can use this
byte[] data = ((IDataIO)sender).Read();
// Or this, the sender is always the concrete
// implementation that abstracts the strategy in use
data = _channel.Read();
}
private DataIO _channel;
}
Obviously you should consider the strategy pattern. I will post the code first and explain later:
public interface IDataIO
{
event DataReceivedEvent DataReceived;
//this the new added method that each IO type should implement.
void SetStrategy();
}
public class SerialIO : IDataIO
{
public void SetStrategy()
{
//put the code that related to the Serial IO.
this.DataReceivedHandler += MyGuiUpdate;
this.DataReceivedHandler += MyDataProcessing;
}
}
public class TcpIO : IDataIO
{
public void SetStrategy()
{
//put the code that related to the Tcp IO.
//I will not implement it because it is a demo.
}
}
public class UdpIO : IDataIO
{
public void SetStrategy()
{
//put the code that related to the Udp IO.
//I will not implement it because it is a demo.
}
}
public class IO
{
IDataIO port = new IDataIO();
public void SetIOType(IDataIO ioType)
{
this.port = ioType;
port.SetStrategy();
}
}
public class IOManager
{
List<IO> ports = new List<IO>();
SerialIO serial = new SerialIO();
TcpIO tcp = new TcpIO();
ports[0].SetIOType(serial);
ports[1].SetIOType(tcp);
}
The interface IDataIO define basics that the all the IO types should implement.
The SerialIO, TcpIO, UdpIO classes derived from IDataIO implement the method SetStrategy() to meet each of their own need.
The IO class owns a field(named port) refers to a IDataIO type, this field can be setted to a certain IO type during the runtime by calling the method SetIOType() defined in the IO
class. Once this method is being called, we know which type the 'port' field refers to, and
then call the SetStrategy() method, it will run the overrided method in one of the IO class.
The IOManager class is the client. when it needs a certain IO type, say SerialIO, it only need to new a IO class and call the SetIOType() method by passing a SerialIO class instance, and all the logic related to the SerialIO type will be setted automatically.
Hope my description can help you.

Mouse Event from one class, how do I listen for it in another class?

I have a UserControl on a Form,
when I MouseMove on that UserControl I want to do something in the Form.
How can I make the Form 'listen' for this event?
I am using Visual C#, .Net framework 3.5, winforms
I suppose you're referring to a use control or something like that.
You can add a public event, and trigger it inside your class when detecting the inner class event.
Then you have to subscribe to the published event in the second class.
This is a sample so that you see the sintax:
public class WithEvent
{
// this is the new published event
public EventHandler<EventArgs> NewMouseEvent;
// This handles the original mouse event of the inner class
public void OriginalEventhandler(object sender, EventArgs e)
{
// this raises the published event (if susbcribedby any handler)
if (NewMouseEvent != null)
{
NewMouseEvent(this, e);
}
}
}
public class Subscriber
{
public void Handler(object sender, EventArgs e)
{
// this is the second class handler
}
public void Subscribe()
{
WithEvent we = new WithEvent();
// This is how you subscribe the handler of the second class
we.NewMouseEvent += Handler;
}
}
If you are talking about Windows Forms (it's not clear from the question) you need to define
a new event in the class who recieves the mouse-event. After reciving it raises a new custom-event. Another class is subcribed to that (custom-event) a recieves notification.
For moe information (it's not something that can be presenteed in a couple of lines)
can have alook here:
How to propagate an Event up to the MainForm?
If you are talking about WPF, there are different concept of events: event routing. If your class is UI element present in UI tree of the component that recieves actually mouse-event, it will be propagated to your class too. So no need of more coding.
To expand a little on the answer from JotaBe, there are two scenarios that I could see you having:
a) class A calls a method in class B, and an exception happens. In this case, you don't need to do anything: exception will walk the stack, until it finds a catch statement. So, really, all you need to do is NOT catch an exception, or if you do need to catch it (for logging purposes and such), then rethrow it.
b) if you need to have a code triggered in some unrelated class, as a result of exception, then the best way is to use events. In your class declare:
public class ClassA
{
public static event EventHandler<Exception> OnException;
public void Notify(Exception ex)
{
if (OnException != null)
{
OnException(this, ex);
}
}
}
and then, in order to be notified, all you need is to
ClassA.OnException += (sender, exeption) =>
{
... some GetHashCode ..
};
... I guess JotaBe already added all necessary example code as I was typing

Passing continuous data between WinForms

I am making a personal WinForms app. In my scenario say I have a C# Form1. Form1 is constantly getting live Exchange data from the Internet. Now I click a button on Form1 and Form2 opens. Now I want some values from Form1 on Form2.
I have a timer on Form2 which can collect data from Form1 but how?
I had tried to use properties but not able to do that as it updates only once as when we initialize Form2.
Any solution?
Also, how can I pass a single instance of a class to both forms, if they are not being created at the same time?
I. Solution: Use a Common Data Source
Method 1: Data Source with Events
Well, if it were me, I would probably not be trying to directly get the data from Form1. Instead, I would set up a common datasource, and then you would even be able to eliminate the timer on Form2 and drive it by when the data comes in if you like. (Or you can leave it and just pull from the datasource as your desired intervals.)
It would be something like this:
Data Source class
public class ExchangeCommonDataSource
{
public event EventHandler NewDataReceived;
public void FireNewDataReceieved()
{
if (NewDataReceived != null)
NewDataReceived();
}
private string mySomeData1 = "";
public string SomeData1
{
get
{
return SomeData1;
}
set
{
SomeData1 = value;
FireNewDataReceieved();
}
}
// properties for any other data
}
Then, when you are opening your forms, you'll just create an instance of ExchangeCommonDataSource, and pass it to both of the forms. In the form that is receiving the data you'll want to create an event handler function, and wherever you pass it the data source, you'll hook up that event.
example: receiving class code
public void HandleDataReceived(object sender, EventArgs e)
{
// display the data
DoSomethingWith(mySource.SomeData1);
// etc...
}
private ExchangeCommonDataSource mySource;
public void SetDataSource(ExchangeCommonDataSource newSource)
{
mySource = newSource;
mySource.NewDataRecieved += new EventHandler(HandleDataReceived);
}
Then, in your first form, you just set the properties you want. You can actually have notifications that specified the actual data to load, either through separate event handlers, or by creating your own derived EventArgs and then using EventHandler<ExchangeCommonEventArgs> instead of a regular event handler.
example: main form data accessor
public void GetDataFromExchange()
{
mySource.SomeData1 = GetSomeData1FromExchange();
}
Also, this way you're not limited to having just those two forms communicate; if you decide to split it up with different forms, you could have each of them have a copy of the data source and each of them could handle the event or new events you define, and you're not tied to a model where you're expecting to communicate directly between each other. This would also allow, for instance, creating a separate class which writes some log data to disk, or whatever else you can imagine, without making significant changes to any of your existing stuff.
II. Extensibility for External Updates
The Dispatcher Base Class
So, what if you want to update to eventually send to another application or another machine even?
Well, this is actually very well accounted for since you've not got any dependencies on the forms left. So, say you wanted to support three methods: the initial, form to form method; sending via a named pipe to another app on the same machine; and TCP/IP to another machine entirely. All you would need to do is to define a class that acts as a dispatcher, hook it up as a receiver, and then you can hook up that object to take the events coming from the form and put the data wherever you want.
It should be fairly straightforward to define an abstract class or interface to do this, and then simply derive a class for any mode you want to support:
example: a notional abstract Dispatcher class
public class ExchangeDataDispatcher :
IDisposable
{
public ExchangeDataDispatcher(ExchangeCommonDataSource parDataSource)
{
myDataSource = parDataSource;
myDataSource.HandleDataReceived +=
new EventHandler(HandleDataReceived);
DispatcherInitialization();
}
private ExchangeCommonDataSource myDataSource;
private void HandleDataReceived(object sender, e EventArgs)
{
// here you could record statistics or whatever about the data
DispatcherHandleDataReceived(EventArgs);
}
protected abstract void DispatcherHandleDataReceived(e EventArgs);
protected abstract void DispatcherShutdown();
// significantly ripped from Microsoft's page on IDisposable
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// call a function which can be overridden in derived
// classes
DispatcherShutdown();
}
// Note disposing has been done.
disposed = true;
}
}
}
see the Microsoft page on IDisposable for some great example code and more information on IDisposable...
Deriving Dispatchers for Other Communication Methods
There's no way to make the form itself derive from this class, but there's no real need since you can just hook up as before. But, as quick example (just notional, not actually implementing the protocols, and you really should really consider the best way to implement these types of things, but I wanted to give you a fairly comprehensive example of what it takes, it's not as simple as the really really naive versions tend to be. )
example: (very) notional Pipe-based Dispatcher
// add these to your using statments
using System.IO.Pipes;
using System.Threading;
// NOTE: take all the async stuff with a grain of salt; this should give you a
// basic idea but there's no way I've gotten it right without actually testing
// and debugging everything. See the link
// http://stackoverflow.com/questions/6710444/named-pipes-server-read-timeout
// for some information on why it has to be done this way: basically timeout
// is not supported for named pipe server streams.
public class ExchangeDataLocalMachineDispatcher :
ExchangeDataDispatcher
{
// see http://www.switchonthecode.com/tutorials/dotnet-35-adds-named-pipes-support
// for some info on named pipes in .NET
public ExchangeDataLocalMachineDispatcher(
ExchangeCommonDataSource parDataSource,
NamedPipeServerStream ServerPipe
) :
base(parDataSource)
{
myPipe = ServerPipe;
// do any extra initialization, etc. here, negotiation for instance
StartPipeThread();
}
private NamedPipeServerStream myPipe;
private ExchangeCommonDataSource myDataSource;
// assuming you have PipeMessage defined and that your handler
// fills them in.
private List<PipeMessage> myOutgoingMessages =
new List<PipeMessage>();
private Thread myPipeThread;
private bool EndPipeListener = false;
private AutoResetEvent myWaitEvent = null;
private AutoResetEvent myDataReadyToGoEvent = null;
// set this to something reasonable for the response timeout
private int WaitTimeout = 10000;
// example: at least every minute there should be data to send
private int WaitForDataToSendTimeout = 60000;
private void StartPipeThread()
{
IAsyncResult LastResult = null;
Action<IAsyncResult> WaitForResult =
(a) =>
{
LastResult = a;
myWaitEvent.Set();
}
myPipeThread = new System.Threading.ThreadStart(
() =>
{
try
{
myWaitEvent = new AutoResetEvent(false);
myPipe.BeginWaitForConnection(
WaitForResult, null
);
bool TimedOut = !myWaitEvent.WaitOne(WaitTimeout);
if (TimedOut || !LastResult.IsCompleted)
throw new Exception("Error: pipe operation error.");
while (!EndPipeListener)
{
byte[] Response = myPipe.BeginRead(
WaitForResult, null
);
myWaitEvent.WaitOne(WaitTimeout);
if (TimedOut || !LastResult.IsCompleted)
throw new Exception("Error: pipe operation error.");
// another assumed function to handle ACKs and such
HandleResponse(Response);
myWaitEvent.Set();
// now wait for data and send
bool TimedOut =
myDataReadyToGoEvent.WaitOne(WaitForDataToSendTimeout);
if (TimedOut || !LastResult.IsCompleted)
throw new Exception("Error: no data to send.");
// an assumed function that will pull the messages out of
// the outgoing message list and send them via the pipe
SendOutgoingMessages();
myDataReadyToGoEvent.Set();
}
myWaitEvent.Set();
}
finally
{
// here you can clean up any resources, for instance you need
// to dispose the wait events, you can leave the pipe for the
// DispatcherShutdown method to fire in case something else
// wants to handle the error and try again... this is all
// fairly naive and should be thought through but I wanted
// to give you some tools you can use.
// can't remember if you're supposed to use .Close
// .Dispose or both off the top of my head; I think it's
// one or the other.
myWaitEvent.Dispose();
myDataReady.Dispose();
myWaitEvent = null;
myDataReady = null;
}
}
);
}
protected PipeMessage[] ConstructEventMessage(e EventArgs)
{
// actually we're not using the event args here but I left it
// as a placeholder for if were using the derived ones.
return
PipeMessage.CreateMessagesFromData(
myDataSource.GetMessageData()
);
}
protected override void DispatcherHandleDataReceived(e EventArgs)
{
// create a packet to send out; assuming that the
// ConstructEventMessage method is defined
myOutgoingMessages.Add(ConstructEventMessage(e));
}
protected override void DispatcherShutdown()
{
// this is called from the base class in the Dispose() method
// you can destroy any remaining resources here
if (myWaitEvent != null)
{
myWaitEvent.Dispose();
}
// etc. and
myPipe.Dispose();
}
// you could theoretically override this method too: if you do, be
// sure to call base.Dispose(disposing) so that the base class can
// clean up if resources are there to be disposed.
// protected virtual void Dispose(bool disposing)
// {
// // do stuff
// base.Dispose(disposing);
// }
}
Phew. Note that I'm very unhappy currently with the length of the StartPipeThread function, and I would definitely be refactoring that.
So, you could also implement this for TCP/IP sockets, or whatever protocol you can imagine, and it's all handled without having to continually modify the classes from the first section.
My apologies for the quality of any of the code there; I am open to suggestion/correction/flaming about it, and I'll do my best to make corrections if you just let me know. :P
III. Putting the Data Where it's Needed
After you have this set up, you'll need to pass the same data to whatever forms are using it. If you're not creating both your forms at the same time, then you'll need some way to get each destination a reference to the same data source. (Note: the numbering of the options is in no way intended to imply these are your only choices!)
Here are a few options for doing so:
Option 1: via Property on your main Form
This method is appropriate if your main form is responsible for creating each of the child forms, for instance, through menu items. You simply create a member variable to hold the data, and wherever you create the data, store a reference to it in that member. If you have multiple instances of the source, you can store them e.g. in a dictionary that allows you to look up the one you need.
example: code for main Form
private ExchangeCommonDataSource myData { get; set; }
// you can also store in something that lets you identify multiple
// possible data sources; in this case, you could use, say, email address
// as a lookup: myData["mickey#example.com"];
//private Dictionary<string, ExchangeCommonDataSource> myData =
// new Dictionary<string, ExchangeCommonDataSource>();
public frmMyMainForm()
{
InitializeComponent();
// ... other initialization for the main form ...
// create the data here and save it in a private member on your
// form for later; this doesn't have to be in the constructor,
// just make sure you save a reference to the source when you
// do create your first form that uses the source.
myData = new ExchangeCommonDataSource();
}
// then, in the methods that actually create your form
// e.g. if creating from a menu item, the handlers
public void FirstFormCreatorMethod()
{
frmFirstForm = new frmFirstForm(myData);
frmFirstForm.MdiParent = this;
frmFirstForm.Show();
}
public void SecondFormCreatorMethod()
{
frmSecondForm = new frmSecondForm(myData);
frmSecondForm.MdiParent = this;
frmSecondForm.Show();
}
Option II: static Properties on your Data Source
This option can be used if the forms are being created externally from the main form, in which case you will not have access to its methods. The idea behind this method is that you want an easy way to find whatever item you need, independent of the main form itself, and by providing a static method, additional data consumers can find the sources on their own using properties accessible with access only to the class declaration and then some sort of key if there can be multiple sources.
example: ExchangeCommonDataSource.cs
// a dummy source class; this is just the parts that were relevant
// to this particular discussion.
public partial class ExchangeCommonDataSource
{
public string Username { get; set; }
public string OptionalString { get; set; }
public int MailboxNumber { get; set; }
public Guid SourceGuid { get; set; }
public long BigNumber { get; set; }
// these static members provide the functionality necessary to look
// retrieve an existing source just through the class interface
// this holds the lookup of Guid -> Source for later retreival
static Dictionary<Guid, ExchangeCommonDataSource> allSources =
new Dictionary<Guid,ExchangeCommonDataSource>();
// this factory method looks up whether the source with the passed
// Guid already exists; if it does, it returns that, otherwise it
// creates the data source and adds it to the lookup table
public static ExchangeCommonDataSource GetConnection(
Guid parSourceGuid, string parUsername, long parBigNumber
)
{
// there are many issues involved with thread safety, I do not
// guarantee that I got it right here, it's to show the idea. :)
// here I'm just providing some thread safety; by placing a lock
// around the sources to prevent two separate calls to a factory
// method from each creating a source with the same Guid.
lock (allSources)
{
ExchangeCommonDataSource RetVal;
allSources.TryGetValue(parSourceGuid, out RetVal);
if (RetVal == null)
{
// using member initializer, you can do this to limit the
// number of constructors; here we only need the one
RetVal = new ExchangeCommonDataSource(parSourceGuid) {
Username = parUsername, BigNumber = parBigNumber
};
allSources.Add(parSourceGuid, RetVal);
}
return RetVal;
}
}
// this function is actually extraneous since the GetConnection
// method will either create a new or return an existing source.
// if you had need to throw an exception if GetConnection was
// called on for existing source, you could use this to retrieve
public static
ExchangeCommonDataSource LookupDatasource(Guid parSourceGuid)
{
// again locking the sources lookup for thread-safety. the
// rules: 1. don't provide external access to allSources
// 2. everywhere you use allSources in the class,
// place a lock(allsources { } block around it
lock (allSources)
{
ExchangeCommonDataSource RetVal;
allSources.TryGetValue(parSourceGuid, out RetVal);
return RetVal;
}
}
// private constructor; it is private so we can rely on the
// fact that we only provide factory method(s) that insert the
// new items into the main dictionary
private ExchangeCommonDataSource(Guid SourceGuid)
{
// if you didn't want to use a factory, you could always do
// something like the following without it; note you will
// have to throw an error with this implementation because
// there's no way to recover.
//lock (allSources)
//{
// ExchangeCommonDataSource Existing;
// ExchangeCommonDataSource.allSources.
// TryGetValue(parSourceGuid, out Existing);
// if (Existing != null)
// throw new Exception("Requested duplicate source!");
//}
// ... initialize ...
}
}
now to access, the client just needs to have some sort of key to access the data:
example: frmClientClass.cs
public partial class frmClientClass
{
ExchangeCommonDataSource myDataSource = null;
public void InitializeSource(Guid parSourceGuid)
{
myDataSource = ExchangeCommonDataSource.GetConnection(parSourceGuid);
}
}
I find this a generally more compelling solution that Option 1, simply because anything that has access to the class and an ID can get the data source, and because it's fairly easy to implement, and it gives automatic support for doing multiple instances of your data source class.
It has fairly low overhead, and since getting a data source is, in most cases, something that is not going to be done in tight loops (and if it were, you would have local copies, not looking them up from a dictionary every time) any small performance loss should be worth the ease of use. And, best of all, even if you start with one data source, you can easily extend your application to more without having to rewrite any code or go to any further effort.
For instance, a very quick way to use this assuming you only have one data source would be just to use a known value for your Dictionary key, and then you just can hard code that in your second for for now. So, for the example, you could just have the empty GUID as your key, and use that for both your forms. i.e. the Main Form or your first data form would call the create method with Guid.Empty to create the data initially, and then you can just use that to access it when the time comes to open your second form.
Option 3: The 'Singleton' Pattern Class
Okay, I'm not going to spend much time or write code for this one, but I would be remiss if I didn't mention it. It's very similar to option 2, except, instead of having a static Dictionary to look up multiple data sources, you create a class that has one instance of the class stored in a static property, and you prevent (via exception) any attempts to create more classes. Then, you set all constructors to private, have them throw exceptions if the static variable already contains an object, and you create a getInstance() method which returns the single instance of the class, creating it if it's null.
Now, there are some little thread-safety trickiness issues with this that you will need to understand to write a traditional singleton, so be sure to understand those (there are questions on StackOverflow dealing with the issue). If you don't need any particular knowledge to construct the instance of the class, you can avoid the issues by simply initializing the variable where you declare it e.g. static MyClass theInstance = new MyClass();, and I highly recommend doing that if you do ever use one.
I have used Singletons in the (fairly distant) past, and it's not that they don't occasionally have their uses, especially in embedded systems. But, this is not an embedded system, and almost every time I used a Singleton in a GUI application, I regretted doing it because I ended up eventually re-writing it into something that would allow multiple instances. If you really just need one copy, all you have to do is put a member variable in the class that uses it, say, your main form, and make sure that you don't ever create but one. Doing this, you could even use the pattern by setting a static flag in the class that you can trigger an exception on; set it to true when you first create the object, and then if that's true you can throw your exception.
Anyway, my personal first rule for when to write a singleton is: don't do it unless you are certain you will never need more than one. If it passes that one, then the second rule is: you are wrong, there is a way it could happen, so just write it as a normal class and handle the singleton-ness of it in some other way. :) Seriously though, the real rule is, just don't do it unless you have get some a very solid reason or a significant benefit from doing it.
Oh, and to reiterate: it's very possible to accomplish the pattern of singleton, without writing the canonical singleton class. The pattern is fine, just do it in a way that when that need for a second instance of that class comes along, there is a very low cost to eliminate the pattern.
Option 4: A Separate Class
Option 4 is very similar to Option 2, but implemented in a second class. (In fact, if you ever think you might have multiple sources of data, it would be worthwhile to just start here, although it's a little more time to set up initially.) Instead of having your static items as members of that class, implement another class that has something like them and provides access. This is a way to decouple the class itself from the creating of it. For example, if you were writing a library, and you wanted to provide several different types of data source, you could implement a base class and then derive your other objects from the base class, and then provide creation mechanisms via a class that gives factory methods to create the different kinds.
In a situation like this you very well may not even want whatever is using your data source to have to know anything about the implementation of the data source classes at all, and only go through the base interface, and this provides an easy way to do that. If you had to write it all as base class static members, then you would be forcing a rewrite of the base every time you derived a new class, and it would also be forcing the base to know something about the derived classes, each of which is, in general, something to avoid. In other words, it's not that it's never useful, but don't do it without very good reason, and don't do it without understanding the implications.
example: code for external class
InfostoreBase.cs
// our data source base class; could do interface instead like:
// public interface IInfostoreBase
public abstract class InfostoreBase
{
public abstract int Information { get; set; }
public abstract string NameOfItem { get; set; }
public abstract decimal Cost { get; set; }
// ... etc ...
}
InfostoreEnterprise.cs
public class InfostoreHomeEdition :
InfostoreBase
{
public override int Information { get { /* ... */ } set { /* ... */ }}
public override string NameOfItem { get { /* ... */ } set { /* ... */ }}
public override decimal Cost { get { /* ... */ } set { /* ... */ }}
public void SetFeatures(string parSomething) { /* ... */ }
}
InfostoreHomeEdition.cs
public class InfostoreEnterpriseEdition :
InfostoreBase
{
public override int Information { get { /* ... */ } set { /* ... */ }}
public override string NameOfItem{ get { /* ... */ } set { /* ... */ }}
public override decimal Cost { get { /* ... */ } set { /* ... */ }}
public void SetBaseDiscount(decimal parSomethingElse) { /* ... */ }
}
InfostoreProvider.cs
public class InfostoreProvider
{
static Dictionary<Guid, InfostoreBase> allSources =
new Dictionary<Guid,InfostoreBase>();
public static InfostoreBase
GetHomeConnection(Guid CustomerKey, string HomeFeatures)
{
lock (allSources)
{
InfostoreBase RetVal;
if (!ValidHomeKey(CustomerKey))
throw new
InvalidKeyException("not valid for Home Edition");
allSources.TryGetValue(CustomerKey, out RetVal);
if (RetVal == null)
{
RetVal = new InfostoreHomeEdition();
allSources.Add(CustomerKey, RetVal);
}
var ActualVersion = (InfostoreHomeEdition) RetVal;
RetVal.SetFeatures(HomeFeatures);
return RetVal;
}
}
public static InfostoreBase
GetEnterpriseConnection(Guid CustomerKey, decimal BaseDiscount)
{
lock (allSources)
{
InfostoreBase RetVal;
if (!ValidEnterpriseKey(CustomerKey))
throw new
InvalidKeyException("not valid for Enterprise Edition");
allSources.TryGetValue(CustomerKey, out RetVal);
if (RetVal == null)
{
RetVal = new InfostoreHomeEdition();
allSources.Add(CustomerKey, RetVal);
}
var ActualVersion = (InfostoreEnterpriseEdition) RetVal;
RetVal.SetBaseDiscount(CostBase);
return RetVal;
}
}
}
code in client class
private InfostoreBase myConnectionSource;
private void Initialize()
{
// ...
myConnectionSource =
InfostoreProvider.GetConnection(
myKey, isEnterprise, myData
);
//...
}
Closing
I think that covers a very good range of possible solutions; none of them is particularly hard to implement, and each has its own benefits and disadvantages. In general I would go for Option 2 or Option 4, but [broken record] it always depends on your exact situation. I think it would be fairly easy to use extend these to handle lots of different situations. And of course if there are any problems, just let me know.
Another possible way to handle this would be to create some interfaces to represent the role of data provider and data receiver, and then you would implement those interfaces on your form. It would be very similar to doing it with a common data source, but instead of running things through an object, you would implement the interfaces and the data can go directly where it is needed. It may be a bit more efficient that doing it through a DataSource, although it's hard to say without knowing all the specifics, but if you are really transferring loads of data putting it through a separate datasource could cost you some efficiency, especially if you never have a need for all the data in one spot.
In the example code here I'm showing what it would look like if you implemented your own event args for different types of data, this also could be used in a common data source for the events if you wanted to be able to have a little more granularity over what got sent when. (Please keep in mind I've typed this all in on the webpage without trying to compile it; this is supposed to give you the idea of how to do it, but its possible (I would estimate 100% change) that I didn't get everything in perfectly. :D)
public class FirstDataKindEventArgs : EventArgs
{
public FirstDataKindEventArgs(int parID, string parName, string parOtherInfo)
{
Id = parId;
Name = parName;
OtherInfo = parOtherInfo;
}
public int ID { get; set; }
public string Name { get; set; }
public string OtherInfo { get; set; }
}
// plus other event arg definitions
public interface IExchangeDataProvider
{
event EventHandler<FirstDataKindEventArgs> FirstDataKindReceived;
event EventHandler<SecondDataKindEventArgs> SecondDataKindReceived;
event EventHandler<ThirdDataKindEventArgs> ThirdDataKindReceived;
}
public interface IExchangeDataReceiver
{
void ConnectDataProvider(IExchangeDataProvider Provider);
}
then in your data providing form you would implement the interface:
public partial class MyProvidingForm : System.Windows.Forms.Form, IExchangeDataProvider
{
// normal form stuff
// ...
#region IExchangeDataProvider
public event EventHandler<FirstDataKindEventArgs> FirstDataKindReceived;
public event EventHandler<SecondDataKindEventArgs> SecondDataKindReceived;
public event EventHandler<ThirdDataKindEventArgs> ThirdDataKindReceived;
public void FireDataReceived(EventArgs Data)
{
FirstDataKindEventArgs FirstKindData = Data as FirstDataKindEventArgs;
if (FirstDataKindEventArgs != null)
if (FirstDataKindReceived != null)
FirstDataKindReceived(FirstKindData);
//... etc.
}
public void GotSomeDataOfTheFirstKind(int TheID, string SomeName, string Other)
{
FirstDataKindEventArgs eArgs =
new FirstDataKindEventArgs(TheId, SomeName, Other);
FireDataReceived(eArgs);
}
and in your receiver form(s) or other classes you wish to receive data:
public partial class FirstDataKindReceivingForm :
System.Windows.Forms.Form,
IExchangeDataReceiver
{
// usual form stuff
// ...
private IExchangeDataProvider myDataProvider;
public void ConnectDataProvider(IExchangeDataProvider Provider)
{
myDataProvider = Provider;
myDataProvider.FirstDataKindReceived +=
new EventHandler<FirstDataKindEventArgs>(
HandleFirstKindOfDataReceived
);
}
private void HandleFirstKindOfDataRecieved (
object sender, FirstDataKindEventArgs
)
{
// do whatever with data
}
}
#endregion
}
and so forth.
edit Form2 's constructor, so that you can pass some values from Form1 while running a new Form2 with .Show or .ShowDialog
Form2 myForm = new Form2(value1, value2, value3 ...);
And on Form2.cs you shall convert (or add a new one) public Form2() to public Form2(var value1, var value 2...)
If you have to send to Form2 continuously data, you may use a shared memory or shared data file.
The answer in the db forum by Mahrous seems to be the simplest http://www.daniweb.com/software-development/csharp/threads/126879/617436#post617436
Some of the other solutions are also valid and may be appropriate depending on the design of the applicaiton.

Is this an Observer Anti-Pattern? (with bonus state machine question)

I am wondering if the following is bad use of the Observer pattern. I know the Subject is supposed to be the one and the listener the many. However, I could end up with more subjects in my application than listeners!
The Players
Form1: Self explanatory
DocumentCreator: Contains a Factory Method and a Strategy for picking a file from a list
Document: Contains information about the document file and a Template method for children
Proposed
IErrorProne: interface for the above players to implement an event, turning them into subjects
Reporting: listens for IErrorProne objects and handles logging/emailing
DocumentState: This is a bonus that Im a bit iffy on. I havent quite settled on a good flow outside of the template. Currently I have a state machine inside the Document class. I want to pull the state machine out of the Document class and into Form1, decoupling the two from each other.
public interface IErrorProne
{
public delegate void ErrorEventDelegate(
object sender,
ErrorEventArgs e
);
public event ErrorEventDelegate ReportError;
}
public abstract class Document : IDisposable, IErrorProne // My Template
{
public void Process()
{
//Error Occured
OnReportError(); // safely triggers error reporting
}
}
public class Reporting
{
static Reporting instance = new Reporting();
public void HandleError(object sender, ErrorEventArgs e);
}
public partial class Form1
{
private DocumentCreator docFactory
= new DocumentCreator(new RandomPicking());
private Document theDoc = null;
private Reporting reporting = Reporting.Instance;
private DocState state = new InitialState();
//DocState not in this example but demonstrates how it might work
public Form1()
{
docFactory.ReportError += reporting.HandleError;
theDoc.ReportError += reporting.HandleError;
docFactory.ReportError += state.HandleError;
theDoc.ReportError += state.HandleError;
}
void BackgroundWork(...)
{
using (theDoc = DocumentFactory.Instance.CreateDocument())
{
if (theDoc != null)
theDoc.Process();
}
}
}
I guess my question is it an Anti-Pattern if I have a Many to One, rather than a One to Many?
If you think of it as publish-subscribe, then it really doesn't matter. If you take the Domain Event style, you can have anything and any number of things publish any given domain event, and anything and any number of things subscribe to domain events.
Many->Many, many->one, one->many are all valid.

Categories