A Behavior created by Haruhiro Isowa with assistance from Michael Washington.
Introduction
This article will show you how to use my PopUp Behavior that will launch a simple Yes/No Popup
and explain how it works so you will be able to tune it to your needs. This PopUp
should make creating PopUp
s in MVVM / VM style easier by generating the PopUp
for you which will save you the time of creating a View and View Model for a Popup
, remove the need for complexity shown by other solutions that uses messaging / services and so forth. This also allows designers to have some control to create PopUp
s without waiting for the programmers to make a View and VM for them.
What HisowaSimplePopUpBehavior Do
This is the PopUp
that it generates, but you can customize by modding the code or by properties on behavior.
These are the Properties. (All properties under Miscellaneous are bindable).
Brush
es are to set your background of the Button
s and PopUp
Window, gradients, images, etc. are ok.
CustomParameter
: object
, you pass to the behavior and when the PopUp
closes it will return that to you. You can pass selected object or ID, etc.
PopUpMessage
: string
, set the message for the PopUp
PopUpNoMessage
: string
, set the text on the No button
PopUpYesMessage
: string
, set the text on the Yes button
ReturnDialogResult
: bool?
, exposes the result of the PopUp
(You can use two-way binding to pass back results. I used it to set IsChecked
on a checkbox
.
ReturnICommand
: ICommand
, The command to run when PopUp
closes. It will pass in a dataholder
class HisowaSimplePopUpBehaviorResult
which will contain the DialogResult (bool?), DataContext
of the Popup
(Probably will not be used for this Popup Behavior ver), and InputParameter
which is your CustomParameter
you have set above.
By the properties of the behavior, you probably can guess what is going to happen. This Behavior
will generate a simple Popup
that you can set text, background values; pass in a parameter (probably useful to put the object in question); allow you to bind the DialogResult
of the PopUp
; and Most importantly run an ICommand
when the PopUp
Closes and passes you the DialogResult
, DataContext
, and the parameter you have passed so your ICommand
can consume it.
Using my HisowaSimplePopUpBehavior
Start by opening a new Silverlight Application. Name it SimplePopUpBehaviorSample
. Add my HisowaSimplePopUpBehavior
class to your solution. Add a reference to System.Windows.Interactivity
, and System.Windows.Controls
. System.Windows.Interactivty
is in Blend SDK. Build your project and open your MainPage.xaml in Expression Blend.
Before we can get started, we will need to have a View
and ViewModel
. Delete the MainPage.xaml in Blend. Add a new Item to the project by Right Clicking on the Project, select Add New Item. On the dialog, set User Control with ViewModel, name the file MainPage.xaml.
Open the MainPage.xaml.
Drag a button on the page. Then look for my behavior HisowaSimplePopUpBehavior
and drag it on the Button
.
.
Now Build and run it from Blend. You should now have a simple Popup
. At this point, it's not doing anything cool.
ViewModel Code
We need to setup some code in the ViewModel
. But before we get started, we will use John Papa's DelegateCommand.cs file. Get it from Delegate Command From John Papa.
Replace MainPageModel.cs code with this:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Data;
using System.ComponentModel;
using System.Windows.Input;
using HisowaPopUpBehaviors;
namespace SimplePopUpBehaviorSample
{
public class MainPageModel : INotifyPropertyChanged
{
public MainPageModel()
{
PopupSimpleResultCommand = new DelegateCommand
(PopupSimpleResult, CanPopupSimpleResult);
}
#region PopupSimpleResultCommand
public ICommand PopupSimpleResultCommand { get; set; }
public void PopupSimpleResult(object param)
{
HisowaSimplePopUpBehaviorResult _result =
(HisowaSimplePopUpBehaviorResult)param;
PopUpResult = _result.DialogResult;
if (_result.InputParameter != null)
{
Message = _result.InputParameter.ToString();
}
}
private bool CanPopupSimpleResult(object param)
{
return true;
}
#endregion
#region PopUpResult
private bool? _PopUpResult;
public bool? PopUpResult
{
get
{
return _PopUpResult;
}
set
{
_PopUpResult = value;
this.NotifyPropertyChanged("PopUpResult");
}
}
#endregion
#region Message
private string _Message;
public string Message
{
get { return _Message; }
private set
{
if (Message == value)
{
return;
}
_Message = value;
this.NotifyPropertyChanged("Message");
}
}
#endregion
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
}
This is just a simple VM that has single ICommand
that sets the Popup
result to the properties (string Message, bool? PopupResult
). It also implements INotifyPropertyChanged
.
*Note: You might need to fix namespaces if you didn't use the same name for the project.
Now Build and let's get back to Blend.
Using the Behavior part2, with Properties
Now that we got all the groundwork done, we can start using the HisowaSimplePopUpBehavior
to its full potential.
First, we will need to make a UI similar to this for this demo.
Bind these Text Values with Element Property Binding.
PopUpMessage
: Your message Textbox
's Text
property
PopUpYes
/NoMessage
: Your Textbox
's Text
property
CustomParameter
: Your Input Textbox
's Text
property (this allows object, it can be anything)
Bind ReturnDialogResult
to Checkbox
's IsChecked
Property, two-way binding.
Build and Run. Now you should be able to change the text on your TextBox
to what you typed in the textbox
. The CheckBox
should be checked if the popup
was closed by the yes button.
Should look like this.
Now we would like to set ReturnICommand
the most important part of the Behavior
. To do this, Databind
the ReturnIcommand
to the PopUpSimpleResultCommand
and Build.
To check that it's working, go back to Visual Studio and put a breakpoint somewhere in the ICommand
you binded. Then Debug in Visual Studio.
Notice that Icommand
is getting HisowaPopUpBehaviors
class which holds the DialogResult
, InputParameter
(CustomParameter
) and DataContext
. You should be able to do a lot with these in your ICommand
.
My Behavior Explained
In this section, I will explain the code of the Behavior. Most of them are dependency properties that allow the databinding
s, so I will skip over those.
This is the Invoke
method, this gets called when the trigger is fired.
#region Invoke
protected override void Invoke(object parameter)
{
ChildWindow _childWindow = new ChildWindow();
_grid = new Grid();
_grid.Width = 300;
_grid.Height = 100;
_grid.ColumnDefinitions.Add(new ColumnDefinition()
{ Width = new GridLength(1, GridUnitType.Star) });
_grid.ColumnDefinitions.Add(new ColumnDefinition()
{ Width = new GridLength(1, GridUnitType.Star) });
_grid.ColumnDefinitions.Add(new ColumnDefinition()
{ Width = new GridLength(1, GridUnitType.Star) });
_grid.RowDefinitions.Add(new RowDefinition()
{ Height = new GridLength(1, GridUnitType.Star) });
_grid.RowDefinitions.Add(new RowDefinition());
_grid.RowDefinitions.Add(new RowDefinition());
TextBlock tbkMessage = new TextBlock();
tbkMessage.Text = PopUpMessage;
tbkMessage.SetValue(Grid.RowProperty, 0);
tbkMessage.SetValue(Grid.ColumnProperty, 0);
tbkMessage.SetValue(Grid.ColumnSpanProperty, 3);
_grid.Children.Add(tbkMessage);
Button btnYes = new Button();
btnYes.Content = PopUpYesMessage;
btnYes.SetValue(Grid.ColumnProperty, 0);
btnYes.SetValue(Grid.RowProperty, 1);
btnYes.Name = "btnYes";
btnYes.Click += new RoutedEventHandler(btnYes_Click);
_grid.Children.Add(btnYes);
Button btnNo = new Button();
btnNo.Content = PopUpNoMessage;
btnNo.SetValue(Grid.ColumnProperty, 2);
btnNo.SetValue(Grid.RowProperty, 1);
btnNo.Name = "btnNo";
btnNo.Click += new RoutedEventHandler(btnNo_Click);
_grid.Children.Add(btnNo);
_grid.Background = BackGroundColorParameter;
btnYes.Background = YesColorParameter;
btnNo.Background = NoColorParameter;
_childWindow.Content = _grid;
PopUp = _childWindow;
PopUp.Closing += new EventHandler<canceleventargs />(PopUp_Closing);
PopUp.Show();
}
#endregion
Basically it creates the UI, sets the event handlers and assigns the properties from the behavior such as background and message. This is where you will tweak to change the UI.
Now the event handling code for the Yes/No buttons.
#region BtnClicks
void btnNo_Click(object sender, RoutedEventArgs e)
{
RemoveButtonHandlers();
PopUp.DialogResult = false;
}
void btnYes_Click(object sender, RoutedEventArgs e)
{
RemoveButtonHandlers();
PopUp.DialogResult = true;
}
private void RemoveButtonHandlers()
{
Button btnYes = (Button)_grid.FindName("btnYes");
btnYes.Click -= new RoutedEventHandler(btnYes_Click);
Button btnNo = (Button)_grid.FindName("btnNo");
btnNo.Click -= new RoutedEventHandler(btnNo_Click);
}
#endregion
This sets the DialogResults
which also closes the PopUp
, and removes the event handlers.
Now the code for PopUpClosing
event:
#region ChildwindowClosing
void PopUp_Closing(object sender, CancelEventArgs e)
{
PopUp.Closing -= new EventHandler<canceleventargs />(PopUp_Closing);
ReturnDialogResultCommand = PopUp.DialogResult;
if (ReturnICommand != null)
{
HisowaSimplePopUpBehaviorResult _result =
new HisowaSimplePopUpBehaviorResult();
_result.DialogResult = PopUp.DialogResult;
_result.DataContext = PopUp.DataContext;
_result.InputParameter = CustomParameter;
ReturnICommand.Execute(_result);
}
}
#endregion
All this does is remove the handler, get the Icommand
from the dependency property, create my datacontainer HisowaSimplePopUpBehaviorResult
, and run the Icommand
passing the HisowaSimplePopUpBehaviorResult
.
Lastly, the DataContainer HisowaSimplePopUpBehaviorResult
class which is in the same file.
public class HisowaSimplePopUpBehaviorResult
{
public bool? DialogResult { get; set; }
public object DataContext { get; set; }
public object InputParameter { get; set; }
}
This is just a simple data holder.
Full Code
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.ComponentModel;
using System.Reflection;
namespace HisowaPopUpBehaviors
{
[System.ComponentModel.Description("Launches a Simple Popup on Event Trigger")]
public class HisowaSimplePopUpBehavior : TargetedTriggerAction<frameworkelement />,
INotifyPropertyChanged
{
private ChildWindow PopUp;
Grid _grid = new Grid();
public HisowaSimplePopUpBehavior()
{ }
#region CustomParameterProperty
public static readonly DependencyProperty CustomParameterProperty =
DependencyProperty.Register("CustomParameter", typeof(object),
typeof(HisowaSimplePopUpBehavior), null);
public object CustomParameter
{
get
{
return base.GetValue(CustomParameterProperty);
}
set
{
base.SetValue(CustomParameterProperty, value);
}
}
#endregion
#region ReturnDialogResultCommandProperty
public static readonly DependencyProperty ReturnDialogResultCommandProperty =
DependencyProperty.Register("ReturnDialogResultCommand", typeof(bool?),
typeof(HisowaSimplePopUpBehavior), null);
public bool? ReturnDialogResultCommand
{
get
{
return (bool?)base.GetValue(ReturnDialogResultCommandProperty);
}
set
{
base.SetValue(ReturnDialogResultCommandProperty, value);
this.NotifyPropertyChanged("ReturnDialogResultCommand");
}
}
#endregion
#region ReturnICommandProperty
public static readonly DependencyProperty ReturnICommandProperty =
DependencyProperty.Register("ReturnICommand", typeof(ICommand),
typeof(HisowaSimplePopUpBehavior), null);
public ICommand ReturnICommand
{
get
{
return (ICommand)base.GetValue(ReturnICommandProperty);
}
set
{
base.SetValue(ReturnICommandProperty, value);
}
}
#endregion
#region PopUpMessageProperty
public static readonly DependencyProperty PopUpMessageProperty =
DependencyProperty.Register("PopUpMessage", typeof(string),
typeof(HisowaSimplePopUpBehavior), null);
public string PopUpMessage
{
get
{
if (base.GetValue(PopUpMessageProperty) == null)
{
return "Are you sure?";
}
else
{
return (string)base.GetValue(PopUpMessageProperty);
}
}
set
{
base.SetValue(PopUpMessageProperty, value);
}
}
#endregion
#region PopUpYesMessageProperty
public static readonly DependencyProperty PopUpYesMessageProperty =
DependencyProperty.Register("PopUpYesMessage", typeof(string),
typeof(HisowaSimplePopUpBehavior), null);
public string PopUpYesMessage
{
get
{
if (base.GetValue(PopUpYesMessageProperty) == null)
{
return "Yes";
}
else
{
return (string)base.GetValue(PopUpYesMessageProperty);
}
}
set
{
base.SetValue(PopUpYesMessageProperty, value);
}
}
#endregion
#region PopUpNoMessageProperty
public static readonly DependencyProperty PopUpNoMessageProperty =
DependencyProperty.Register("PopUpNoMessage", typeof(string),
typeof(HisowaSimplePopUpBehavior), null);
public string PopUpNoMessage
{
get
{
if (base.GetValue(PopUpNoMessageProperty) == null)
{
return "No";
}
else
{
return (string)base.GetValue(PopUpNoMessageProperty);
}
}
set
{
base.SetValue(PopUpNoMessageProperty, value);
}
}
#endregion
#region BackgroundColor
public static readonly DependencyProperty BackGroundColorParameterProperty =
DependencyProperty.Register("BackGroundColorParameter",
typeof(System.Windows.Media.Brush), typeof(HisowaSimplePopUpBehavior), null);
public System.Windows.Media.Brush BackGroundColorParameter
{
get
{
return (System.Windows.Media.Brush)base.GetValue
(BackGroundColorParameterProperty);
}
set
{
base.SetValue(BackGroundColorParameterProperty, value);
}
}
#endregion
#region YesColor
public static readonly DependencyProperty YesColorParameterProperty =
DependencyProperty.Register("YesColorParameter",
typeof(System.Windows.Media.Brush), typeof(HisowaSimplePopUpBehavior), null);
public System.Windows.Media.Brush YesColorParameter
{
get
{
return (System.Windows.Media.Brush)base.GetValue
(YesColorParameterProperty);
}
set
{
base.SetValue(YesColorParameterProperty, value);
}
}
#endregion
#region NoColor
public static readonly DependencyProperty NoColorParameterProperty =
DependencyProperty.Register("NoColorParameter",
typeof(System.Windows.Media.Brush), typeof(HisowaSimplePopUpBehavior), null);
public System.Windows.Media.Brush NoColorParameter
{
get
{
return
(System.Windows.Media.Brush)base.GetValue(NoColorParameterProperty);
}
set
{
base.SetValue(NoColorParameterProperty, value);
}
}
#endregion
#region Invoke
protected override void Invoke(object parameter)
{
ChildWindow _childWindow = new ChildWindow();
_grid = new Grid();
_grid.Width = 300;
_grid.Height = 100;
_grid.ColumnDefinitions.Add(new ColumnDefinition()
{ Width = new GridLength(1, GridUnitType.Star) });
_grid.ColumnDefinitions.Add(new ColumnDefinition()
{ Width = new GridLength(1, GridUnitType.Star) });
_grid.ColumnDefinitions.Add(new ColumnDefinition()
{ Width = new GridLength(1, GridUnitType.Star) });
_grid.RowDefinitions.Add(new RowDefinition()
{ Height = new GridLength(1, GridUnitType.Star) });
_grid.RowDefinitions.Add(new RowDefinition());
_grid.RowDefinitions.Add(new RowDefinition());
TextBlock tbkMessage = new TextBlock();
tbkMessage.Text = PopUpMessage;
tbkMessage.SetValue(Grid.RowProperty, 0);
tbkMessage.SetValue(Grid.ColumnProperty, 0);
tbkMessage.SetValue(Grid.ColumnSpanProperty, 3);
_grid.Children.Add(tbkMessage);
Button btnYes = new Button();
btnYes.Content = PopUpYesMessage;
btnYes.SetValue(Grid.ColumnProperty, 0);
btnYes.SetValue(Grid.RowProperty, 1);
btnYes.Name = "btnYes";
btnYes.Click += new RoutedEventHandler(btnYes_Click);
_grid.Children.Add(btnYes);
Button btnNo = new Button();
btnNo.Content = PopUpNoMessage;
btnNo.SetValue(Grid.ColumnProperty, 2);
btnNo.SetValue(Grid.RowProperty, 1);
btnNo.Name = "btnNo";
btnNo.Click += new RoutedEventHandler(btnNo_Click);
_grid.Children.Add(btnNo);
_grid.Background = BackGroundColorParameter;
btnYes.Background = YesColorParameter;
btnNo.Background = NoColorParameter;
_childWindow.Content = _grid;
PopUp = _childWindow;
PopUp.Closing += new EventHandler<canceleventargs />(PopUp_Closing);
PopUp.Show();
}
#endregion
#region BtnClicks
void btnNo_Click(object sender, RoutedEventArgs e)
{
RemoveButtonHandlers();
PopUp.DialogResult = false;
}
void btnYes_Click(object sender, RoutedEventArgs e)
{
RemoveButtonHandlers();
PopUp.DialogResult = true;
}
private void RemoveButtonHandlers()
{
Button btnYes = (Button)_grid.FindName("btnYes");
btnYes.Click -= new RoutedEventHandler(btnYes_Click);
Button btnNo = (Button)_grid.FindName("btnNo");
btnNo.Click -= new RoutedEventHandler(btnNo_Click);
}
#endregion
#region ChildwindowClosing
void PopUp_Closing(object sender, CancelEventArgs e)
{
PopUp.Closing -= new EventHandler<canceleventargs />(PopUp_Closing);
ReturnDialogResultCommand = PopUp.DialogResult;
if (ReturnICommand != null)
{
HisowaSimplePopUpBehaviorResult _result =
new HisowaSimplePopUpBehaviorResult();
_result.DialogResult = PopUp.DialogResult;
_result.DataContext = PopUp.DataContext;
_result.InputParameter = CustomParameter;
ReturnICommand.Execute(_result);
}
}
#endregion
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
public class HisowaSimplePopUpBehaviorResult
{
public bool? DialogResult { get; set; }
public object DataContext { get; set; }
public object InputParameter { get; set; }
}
}
Also see: HisowaModPopUpBehavior
This variation will allow you to use your own View and View Model and inject it into the popup
.