I have a WPF project which uses XAML and C#. It adheres (as best as I know) to the MVVM methodology.
As part of it, I have used a mediator class (the 'Gang of Four' design). You register for callbacks, and other classes can notify registered classes in the case of certain events. For example, some parts of the program need to know when the data has been loaded from the database, so they can register to the database and receive a callback when the loading is done.
The 'Register' part of the mediator looks like this:
public void Register(Action<Object> callback, ViewModelMessages message)
{
internalList.AddValue(message, callback);
}
Classes can register themselves, like so:
Mediator.Mediator.Instance.Register(
(Object o) =>
{
if (o == null)
return;
// Perform action using 'o'.
}, Mediator.Mediator.ViewModelMessages.SelectedCharacterChanged);
This all works well and good, and my question isn't exactly one of right or wrong, but one of a more elegant design.
One of my callbacks needs to send a boolean value along with it. But Action(object) (I can't use the angular brackets here) has a problem with that when it comes to the callback. O (in the second piece of code) needs to be nullable. If I were to do something like this:
Mediator.Mediator.Instance.Register(
(Object o) =>
{
// o is boolean
if (o == null)
return;
if( (o as bool) == true)
// Do action
}, Mediator.Mediator.ViewModelMessages.AddNewCharacterMode);
The program will tell me a bool is not nullable (indeed it is not). I will assume this is going to be a problem for all non nullable types like int and what not.
There are some solutions, but none of them elegant or simple.
The first would be to create a class that, for this instance, just holds a bool.
The second is to alter the Action(object) to be Action(bool). Well this works in this instance, but I use this method for other things, most of which are objects. So then I'd have to create a second set of methods in the mediator to handle the bool, which seems not very good.
The third, which leads on from the second, is to create a generic mediator, but this also isn't good because I'd need a new instance of the mediator for each type. Again it would work, but I think it's going to make things confusing.
If anyone has an elegant solution, I would be appreciative. I feel it can't be a rare problem, so I'm hoping that there's some established way of doing this.
Below is the code for the mediator class:
public sealed class Mediator
{
public enum ViewModelMessages { SearchPaneViewModel = 1, CharacterFormViewModel = 2, SelectedCharacterChanged = 3, AddNewCharacterMode = 4 };
#region Data
static readonly Mediator instance = new Mediator();
private volatile object locker = new object();
MultiDictionary<ViewModelMessages, Action<Object>> internalList = new MultiDictionary<ViewModelMessages, Action<Object>>();
#endregion
#region Ctor
//CTORs
static Mediator()
{
}
private Mediator()
{
}
#endregion
#region Public Properties
/// <summary>
/// The singleton instance
/// </summary>
public static Mediator Instance
{
get
{
return instance;
}
}
#endregion
#region Public Methods
/// <summary>
/// Registers a Colleague to a specific message
/// </summary>
/// <param name="callback">The callback to use
/// when the message it seen</param>
/// <param name="message">The message to
/// register to</param>
public void Register(Action<Object> callback, ViewModelMessages message)
{
internalList.AddValue(message, callback);
}
/// <summary>
/// Notify all colleagues that are registed to the
/// specific message
/// </summary>
/// <param name="message">The message for the notify by</param>
/// <param name="args">The arguments for the message</param>
public void NotifyColleagues(ViewModelMessages message, object args)
{
if (internalList.ContainsKey(message))
{
//forward the message to all listeners
foreach (Action<object> callback in internalList[message])
callback(args);
}
}
#endregion
}
EventArgs
base class, so you getEventHandler<TEventArgs>
as a generic delegate, withobject sender, TEventArgs args
as a signature. So... Indeed there's an established way of doing this: events! \$\endgroup\$Nullable<T>
is a value type that has nullable semantics. \$\endgroup\$ObservableCollection
? \$\endgroup\$