OpenLightGroup Blog

rss

Blogs from OpenLightGroup.net


Silverlight Behavior : HisowaModPopUpBehavior

This is a different variation of my previous PopUp Behavior. If you are unfamiliar with my previous one visit the link, this is built on it and assumes you get the general idea.

This one will allow you to make you own View and View Model and inject it into my generated pop up. Note this one will create the OK/Cancel button like the previous one.

Sample 

 Sample App, The second section.

 Sample project

Code only.

Notes

  • This variation will allow you to use your own View and View Model
  • This behavior will create its own Yes / No button (more on reasoning later)
  • Like the previous it will return the Result container class, HisowaModPopUpResult
  • HisowaModPopUpResult will pass a DataContext, which is the DataContext of your View Model.
  • I will explain you the the parts of the code that have changed so you will be able to customize it / fix it.

 

In Action

image

Like the last one, it is attached to the button. The behavior will open the Pop up on button click event, no code behind.

image

The Calender control values will be passed to Main View Model by the DataContext in HisowaModPopUpResult.

 

How do I use this one?

1) Add a reference to System.Windows.Interactivity, and System.Windows.Controls. System.Windows.Interactivty is in Blend SDK.

2) Add my HisowaModPopUpBehavior.cs to your project.

3) Create a View + View Model

3a) Open your project in Blend.

3b) Right click your project, Select Add New Item…

image

3c) Select UserControl with ViewModel call it View1.xaml

image

3d) Make a View Without the OK / Cancel. (here’s mine)

image 
Its default canvas, and size to auto. Be sure to set a actual pixel if you are using canvas. The way canvas lays out control is by Margin of the closest X / Y border, which will lead to weird UI. (specifically it will try to fit it in as small of space as possible as long as it meets the Margin, for mine the margin for the left calendar is left and top, right calendar has it for right and bottom. This results in overlapping controls.)

3e) Build >> go back to Visual studio and make your ViewModel. here’s mine.

 

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Text;
  4: using System.Windows.Data;
  5: using System.ComponentModel;
  6: 
  7: namespace SimplePopUpBehaviorSample
  8: {
  9: 	public class View1Model : INotifyPropertyChanged
 10: 	{
 11: 		public View1Model()
 12: 		{
 13: 			
 14: 		}
 15: 
 16:         #region DateStartValueProperty
 17: 
 18:         private DateTime _DateStartValueProperty;
 19:         public DateTime DateStartValueProperty
 20:         {
 21:             get
 22:             {
 23:                 return this._DateStartValueProperty;
 24:             }
 25:             set
 26:             {
 27:                 this._DateStartValueProperty = value;
 28:                 this.NotifyPropertyChanged("DateStartValueProperty");
 29:             }
 30:         }
 31:         #endregion
 32: 
 33:         #region DateEndValueProperty
 34:         private DateTime _DateEndValueProperty;
 35:         public DateTime DateEndValueProperty
 36:         {
 37:             get
 38:             {
 39:                 return this._DateEndValueProperty;
 40:             }
 41:             set
 42:             {
 43:                 this._DateEndValueProperty = value;
 44:                 this.NotifyPropertyChanged("DateEndValueProperty");
 45:             }
 46:         }
 47:         #endregion
 48: 
 49: 		#region INotifyPropertyChanged
 50: 		public event PropertyChangedEventHandler PropertyChanged;
 51: 
 52: 		private void NotifyPropertyChanged(String info)
 53: 		{
 54: 			if (PropertyChanged != null)
 55: 			{
 56: 				PropertyChanged(this, new PropertyChangedEventArgs(info));
 57: 			}
 58: 		}
 59: 		#endregion
 60: 	}
 61: }

Only properties to store dates

 

3f) build

4) Go back to Blend and Bind your Calendar selected date to the View Model Property, (Two-way).

 

 

image

5) Go Back to Visual Studio and Add ICommand to run when the PopUp is Closed on the Main View Model.

  1: #region PopupModResultCommand
  2:         public ICommand PopupModResultCommand { get; set; }
  3:         public void PopupModResult(object param)
  4:         {
  5:             //cast to my DataContainer
  6:             HisowaModPopUpBehaviorResult _result = (HisowaModPopUpBehaviorResult)param;
  7: 
  8:             //get the dialogResult
  9:             View1Model vm = (View1Model)_result.DataContext;
 10: 
 11:             //get the input if exists
 12:             if (vm != null)
 13:             {
 14:                 DateStart = vm.DateStartValueProperty;
 15:                 DateEnd = vm.DateEndValueProperty;
 16:             }
 17:         }
 18: 
 19:         private bool CanPopupModResult(object param)
 20:         {
 21:             return true;
 22:         }
 23:         #endregion
 24: 
 25:       

Notice it returns HisowaModPopUpResult and I get the datacontext from it. Its cast to View1Model and I get the dates from it.

 

6) Add the Properties to store dates

  1:  #region DateStart
  2:         private DateTime _DateStart;
  3:         public DateTime DateStart
  4:         {
  5:             get { return _DateStart; }
  6:             private set
  7:             {
  8:                 if (DateStart == value)
  9:                 {
 10:                     return;
 11:                 }
 12:                 _DateStart = value;
 13:                 this.NotifyPropertyChanged("DateStart");
 14:             }
 15:         }
 16:         #endregion
 17: 
 18:         #region DateEnd
 19:         private DateTime _DateEnd;
 20:         public DateTime DateEnd
 21:         {
 22:             get { return _DateEnd; }
 23:             private set
 24:             {
 25:                 if (DateEnd == value)
 26:                 {
 27:                     return;
 28:                 }
 29:                 _DateEnd = value;
 30:                 NotifyPropertyChanged("DateEnd");
 31:             }
 32:         }
 33:         #endregion

 

7) Go back to your Main View, and Drag my Behavior on a Control.

image 

8) Set your CustomUI to the View you have created

image

9) Databind the ReturnICommand to the ICommand we created.

image

10) Make a UI that can use the Properties that got updated by ICommand. (mine is the 2 dates). And Databind.

image

11) Build, Run, Test.

 

 

 

Behavior Code Explained.

  1: using System;
  2: using System.Windows;
  3: using System.Windows.Controls;
  4: using System.Windows.Input;
  5: using System.Windows.Interactivity;
  6: using System.ComponentModel;
  7: using System.Reflection;
  8: 
  9: namespace HisowaPopUpBehaviors
 10: {
 11:     [System.ComponentModel.Description("Launches a Popup with custom UI on Event Trigger")]
 12:     public class HisowaModPopUpBehavior : TargetedTriggerAction, INotifyPropertyChanged
 13:     {
 14:         private ChildWindow PopUp;
 15:         Grid _grid = new Grid();
 16: 
 17:         private StackPanel PopUpContent;
 18: 
 19:         //constructor
 20:         public HisowaModPopUpBehavior()
 21:         { }
 22: 

Pretty standard stuff, except it has a ChildWindow, Grid, and StackPanel as class variables.

  1: #region CustomUI
  2:         public static readonly DependencyProperty CustomUIProperty = DependencyProperty.Register("CustomUI", typeof(UserControl), typeof(HisowaModPopUpBehavior), null);
  3: 
  4:         public UserControl CustomUI
  5:         {
  6:             get
  7:             {
  8:                 return (UserControl)base.GetValue(CustomUIProperty);
  9:             }
 10:             set
 11:             {
 12:                 base.SetValue(CustomUIProperty, value);
 13:             }
 14:         }
 15:         #endregion
 16: 

Dependency property to set your User Control to the Behavior.

  1:  protected override void OnAttached()
  2:         {
  3:             base.OnAttached();
  4: 
  5:             StackPanel stpnl = new StackPanel();
  6:             stpnl.Children.Add(CustomUI);
  7: 
  8:             stpnl.SetValue(Grid.RowProperty, 0);
  9:             stpnl.SetValue(Grid.RowSpanProperty, 2);
 10:             stpnl.SetValue(Grid.ColumnProperty, 0);
 11:             stpnl.SetValue(Grid.ColumnSpanProperty, 3);
 12: 
 13:             PopUpContent = stpnl;
 14:         }

This is where your usercontrol is set into the Behavior, on attached it will jam you usercontrol into a stackpanel, which sits in a Grid (that holds the whole window). This is where you can tweak it to your needs for the layout.

  1: 
  2:         #region ChildwindowClosing
  3: 
  4:         //Runs an Icommand when the Popup is closing
  5:         //you can change what it passes to Icommand to whatever you like
  6:         //be sure that your method can consume them
  7: 
  8: 
  9:         void PopUp_Closing(object sender, CancelEventArgs e)
 10:         {
 11:             PopUp.Closing -= new EventHandler(PopUp_Closing);
 12: 
 13:             ReturnDialogResultCommand = PopUp.DialogResult;
 14: 
 15:             if (ReturnICommand != null)
 16:             {
 17:                 HisowaModPopUpBehaviorResult _result = new HisowaModPopUpBehaviorResult();
 18:                 _result.DialogResult = PopUp.DialogResult;
 19:                 _result.DataContext = ((FrameworkElement)CustomUI.Content).DataContext;
 20:                 _result.InputParameter = CustomParameter;
 21: 
 22:                 ReturnICommand.Execute(_result);
 23:             }
 24: 
 25:             PopUp.Content = null;
 26:         }
 27: 
 28:         #endregion

This is the code it runs when the childwindow is closing. Sets the dialog result property on the Behavior, creates a the Container HisowaModPopUpBehaviorResult to store the result, the data context of the UI you injected, and the input parameters. Pretty much the same as the “simple” except the datacontext is actually being used to pass in your UI’s datacontext.

  1: public class HisowaSimplePopUpBehaviorResult
  2:     {
  3:         public bool? DialogResult { get; set; }
  4:         public object DataContext { get; set; }
  5:         public object InputParameter { get; set; }
  6:     }

The dataContainer that gets passed.

 

Why does it make the Yes, No button for me.

The simple explanation for this is by doing it this way I don’t make your View model have a reference to the Childwindow to set dialog result to close it or make you write code behind. This idea behind this popUp behavior was so A) you do not have to make crazy code with services, messaging or B) allow you to have popUp without your code behind or View Model have a reference to your childwindow.





Comments are closed.
Showing 1 Comment
Avatar  ADefWebserver 7 years ago

Great! All my Popup worries are over :) I pointed my Popup article on CodeProject to this one.