Friday, December 24, 2010

Blog Post: Adding an Extension Method in WPF to Save the Window Position

While factoring my recent project, I found the need to simplify what I was doing for saving window positions to the user profile.  I decided to use the properties available to a WPF application (you can find several references on the blogosphere about how to add a new property to user settings), but today my focus was on simplifying and reusing code.

One of the language novelties that I came across a while ago was related to extension methods ? that is, adding a method to a class that ?seemed? to extend the functionality of the class.   In reality, it is language shorthand for a static method that manipulates a class ? yet does nothing with class internals.  Granted, syntactically, this is new for us ?Old Dogs? and has the appearance of something cool, but under the hood, we know what is is really doing once we read the code <smile>.

/// Saves the window position to the given property name or   /// if null, generates a name based on the Window.Name property.  /// </summary>  /// <param name="window">  /// The window.  /// </param>  /// <param name="propertyName">  /// The property name to save the position.  /// </param>   public   static  void   SaveWindowPosition(      this Window window,      string propertyName = null)  {      if (propertyName == null)      {          propertyName = "Ux" + window.Name + "Position";      }        if (window.WindowState != WindowState.Minimized)      {          Properties.Settings.Default[propertyName] =              string.Format(                  "{0}, {1}, {2}, {3}, {4}",                   window.WindowState,                   window.Left,                   window.Top,                   window.Width,                   window.Height);      }  }    /// <summary>  /// Loads the window position from the given property name or   /// if null, generates a name based on the Window.Name property.  /// </summary>  /// <param name="window">  /// The window.  /// </param>  /// <param name="propertyName">  /// The property name for loading the position.  /// </param>  /// <returns>  /// The true on success.  /// </returns>  public  static  bool  LoadWindowPosition(      this Window window,                  string propertyName = null)  {      bool loadedPosition = false;            if (propertyName == null)      {          propertyName = "Ux" + window.Name + "Position";      }        if (!string.IsNullOrWhiteSpace((string)Properties.Settings.Default[propertyName]))      {          string[] position =              ((string)Properties.Settings.Default[propertyName]).Split(',');          try          {              // Parse all components first, then set the new window state & position              WindowState state =                   (WindowState)Enum.Parse(typeof(WindowState), position[0]);              int left = int.Parse(position[1]);              int top = int.Parse(position[2]);              int width = int.Parse(position[3]);              int height = int.Parse(position[4]);                window.WindowState = state;              window.Left = left;              window.Top = top;              window.Width = width;              window.Height = height;              window.WindowStartupLocation = WindowStartupLocation.Manual;                loadedPosition = true;          }          catch (Exception e)          {              loadedPosition = false;          }      }        return loadedPosition;  }

The nice feature about these extensions is that from a coding perspective, I can reuse the code for each Window that I create, assuming that my positioning for each child window will be based upon the name ? in my case, this is desired.  You many change your setting moniker to whatever you desire but I expect the code will be useful for whatever you finally decide for your user experience.

In general, I use these methods in the Initialize() and Closed() event handlers.   I use the default for the class Initialize() and after initialize the base class, I add the following:

InitializeComponent();    if (!this.LoadWindowPosition())  {      this.WindowStartupLocation = WindowStartupLocation.CenterScreen;      this.Width = 800;      this.Height = 700;  }    this.RefreshChildData();

I also add a ?Closed? event handler such as "Closed=OnClosed? for the class which is basically defined as:

private  void  OnClosed(      object sender,      EventArgs e)  {      this.SaveWindowPosition();  }

Note that the overall property storage is handled via a Save() call at the application level, otherwise these updates to the properties are not written to the configuration settings.

Ashley Scott Michelle Behennah Julie Benz Saira Mohan Brittny Gastineau

No comments:

Post a Comment