As promised here is the version of observer pattern with Event & Delegate. Personally I am not a big fan of this solution, although it does remove quite a bit of code and show how to use a push model with the observer pattern. Next time around I will show a more elegant solution by using Event Aggregator.
But for now lets see how I implemented Observer Pattern with Event/Delegate.
First I tackled the Subject of our class, the thing you will see different is there is an instance object called TextChanged and is an EventHandler, the second change is it Notify method. I also removed the ISubject interface just because there isn’t really a need for it in this example and to make things simple.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
using System; using System.Collections.Generic; namespace EventDelegatePattern { public class Subject { public event EventHandler<TextLangChangedEventArgs> TextChanged; private readonly IList<string> _stateList = new List<string>(); public Subject() { InitState(); } private void InitState() { _stateList.Add("Hello"); _stateList.Add("World"); _stateList.Add("Goodbye"); _stateList.Add("Cat"); _stateList.Add("Dog"); _stateList.Add("Apple"); _stateList.Add("Man"); _stateList.Add("Women"); _stateList.Add("Groovy"); } private string CurrentTextToDisplay { get { var random = new Random(); var i = random.Next(_stateList.Count); return _stateList[i]; } } public void Notify() { if (TextChanged != null) { TextChanged(this, new TextLangChangedEventArgs(CurrentTextToDisplay)); } } } } |
From the above code you will see that there is an object called TextLangChangedEventArgs, that is basically our data object that would be pushed to the observer. Here is how it looks like, the important part is that it extends/inherits from EventArgs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
using System; namespace EventDelegatePattern { public class TextLangChangedEventArgs: EventArgs { public TextLangChangedEventArgs(string newLang) { NewLanguage = newLang; } public string NewLanguage { get; private set; } } } |
Finally back to our WPFApp, we again have 2 labels the Turkish and English one, but they both don’t know anything about the Subject which is a good thing, so that it is loosely coupled. In order for the subject to hook into them they provide a signature where the event will call it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
using System.Windows.Controls; using EventDelegatePattern; namespace WPFApp { /// <summary> /// Interaction logic for EnglishLableControl.xaml /// </summary> public partial class EnglishLableControl : UserControl { public EnglishLableControl() { InitializeComponent(); } public void Update(object source, TextLangChangedEventArgs args) { label1.Content = args.NewLanguage; } } } |
Turkish UserControl does the translation of English to Turkish
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
using System.Collections.Generic; using System.Windows.Controls; using EventDelegatePattern; namespace WPFApp { /// <summary> /// Interaction logic for TurkishLabelControl.xaml /// </summary> public partial class TurkishLabelControl : UserControl { private IDictionary<string, string> _dict = new Dictionary<string, string>(); public TurkishLabelControl() { InitializeComponent(); InitDict(); } private void InitDict() { _dict.Add("Hello", "Merhaba"); _dict.Add("World", "Dünya"); _dict.Add("Goodbye", "Güle Güle"); _dict.Add("Cat", "Kedi"); _dict.Add("Dog", "Köpek"); _dict.Add("Apple", "Elma"); _dict.Add("Man", "Adam"); _dict.Add("Women", "Kadin"); } public void Update(object source, TextLangChangedEventArgs args) { label1.Content = _dict.ContainsKey(args.NewLanguage) ? _dict[args.NewLanguage] : "Cannot find it in turkish"; } } } |
Last but not least here is the WPFApp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
using System.Windows; using EventDelegatePattern; namespace WPFApp { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { private Subject _subject = new Subject(); public Window1() { InitializeComponent(); _subject.TextChanged += TurkishLabel.Update; _subject.TextChanged += EnglishLabel.Update; } private void button1_Click(object sender, RoutedEventArgs e) { _subject.Notify(); } } } |
I have not posted the XAML code but one can download the source and solution.
For next time I would like to show a more elegant solution called Event Aggregator which is a pretty cool pattern introduced by Martin Flower that allows one to write extensible code.
Leave A Comment