The observer pattern for UI events

We will use the GoF observer pattern to handle UI events in an automatic fashion. The moment an expression gets changed in the textbox, the window should get a notification about it, and if the expression is valid, the resulting expression will be rendered on the screen.

Note

While implementing the observer pattern, we have two classes-the Subject class, which represents the event source, and the Observer class, which is a list of observers (observer who are interested in listening to the event. Whenever there is a change in the text, the Subject class which represents the event source sends notification to all the sinks who have subscribed to the event.

We have already mentioned that in the case of the observer pattern, we communicate between the event source and event sinks. The event source is represented using the Subject class, and the event sink is represented using an Observer class. Let us dissect the implementation of the Observer class:

    public abstract class BaseObserver 
    { 
      protected delegate void 
      ExpressionEventHandler(string expression); 
      protected ExpressionEventHandler ExpressionChangedEvent; 
      protected Control _ctrl = null; 
      public abstract void Observer_ExpressionChangedEvent(string     
      expression);

We declare a delegate which will act as an event handler, and to make the class handle all the WPF controls, we mark the event subscriber as a WPF control. The concrete class can hold any object derived from Control:

    public BaseObserver(Control ctrl) 
    { 
      this.ExpressionChangedEvent +=  
      new ExpressionEventHandler( 
      Observer_ExpressionChangedEvent); 
      this._ctrl = ctrl; 
    } 

In the constructor, we initialize the delegate with an address of an abstract method. This will automatically get wired to the concrete class implementation of the method. We are, effectively, using the GoF template method pattern for the observer implementation. The concrete class is mandated to implement the Observer_ExpressionChangedEvent method:

    private void OnChange(string expression) 
    { 
      if (ExpressionChangedEvent != null) 
      ExpressionChangedEvent(expression); 
    } 
    public void Update(string expression) 
    { 
      OnChange(expression); 
    } 
  } 

Now, we will try to write the Subject class which acts as an event source. The Subject class will iterate through the list of observers to dispatch the events which the observers are interested in. Any change in the expression textbox will be relayed to the window object, which acts as a receiver of the events:

    public class Subject 
    { 
      List<BaseObserver> observers = new List<BaseObserver>(); 
      private delegate void NotifyHandler(string expression); 
      private event NotifyHandler NotifyEvent; 
 
      public Subject(){ 
        this.NotifyEvent += new NotifyHandler(Notify); 
      } 
 
      public void UpdateClient(string expression){ 
        OnNotify(expression); 
      } 
 
      private void OnNotify(string expression){ 
        if (NotifyEvent != null) 
        NotifyEvent(expression); 
      } 
 
      private void Notify(string expression){ 
        foreach (BaseObserver b in observers) 
        b.Update(expression); 
      } 
 
      public void RegisterClient(BaseObserver obs){ 
        observers.Add(obs); 
      } 
    } 

The BaseObserver class given in the preceding code snippet is an abstract class, and we need to create a concrete class which implements Observer_ExpressionChangedEvent. The concrete implementation listing is given as follows:

    class ExpressionObserver : BaseObserver 
    { 
      public ExpressionObserver(Window _win) : 
      base(_win){ } 
 
      public override void  
      Observer_ExpressionChangedEvent(string expression) 
      { 
        MainWindow mw = this._ctrl as MainWindow; 
        mw.Expr = expression; 
        ExpressionBuilder builder = new  
        ExpressionBuilder(expression); 
        Exp expr_tree = builder.GetExpression(); 
 
        if ( expr_tree != null ) 
          mw.Render(); 
      } 
    } 

Let us see how we can connect the Subject and Observer class. See the MainWindow.cs module in the source code associated with this book. A snippet of the code is given as follows:

    _observer = new ExpressionObserver(this); 
    _subject = new Subject(); 
    _subject.RegisterClient(_observer); 

Whenever there is change in the text, the rendering routine will be notified. The rendering routine uses WPF 2D graphics transformations to plot the equation:

    private void text_changed(object sender, TextChangedEventArgs e) 
    { 
      if ( _subject != null ) 
      _subject.UpdateClient(this.ExprText.Text); 
    } 
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.84.155