I have a long running command that is started via a context menu. The context menu remains open till the command execution ends. I find this awkward. Tow questions:
Is that the way Windows programs should behave?
Is there a way to close the menu before the command is executed?
The application is MVVM and I would not like to program against the UI directly. Below is a simple code showing the behavior.
Please note: In the real application a wait cursor is displayed during command execution. Also, I do not want to run the command execution in a background thread but rather have the user wait till the command is finished.
XAML:
Window x:Class="WpfApp4__Various_Tests_.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp4__Various_Tests_"
Title="MainWindow" Height="300" Width="300"
x:Name="root">
<Grid>
<Rectangle
Fill="ForestGreen"
Height="100" Width="200" Margin="10"
VerticalAlignment="Top"
>
<Rectangle.ContextMenu>
<ContextMenu>
<MenuItem
Header="Long running ommand"
Click="MenuItem_Click"
/>
</ContextMenu>
</Rectangle.ContextMenu>
</Rectangle>
</Grid>
Code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
Thread.Sleep(3000);
}
}
The menu can't be closed because you block the UI thread with the handler. To fix the example you show here, use this:
private async void MenuItem_Click(object sender, RoutedEventArgs e)
{
await Task.Delay(TimeSpan.FromSeconds(3000));
}
In your actual program, you may or may not be calling code that is inherently async. If it is, you can do the same as above and await the result. If not, you should wrap the code in an async-friendly task. At the bare minimum, that would look something like this:
private async void MenuItem_Click(object sender, RoutedEventArgs e)
{
await Task.Run(() => Thread.Sleep(3000));
}
And I do mean bare minimum. Without knowing more about your long-running task, it's impossible to give anything more specific in the way of advice. However, a couple of important points:
The long-running task may require periodic interaction with objects owned by the UI thread. If you are strictly using data binding, WPF will automatically handle cross-thread notifications that occur via INotifyPropertyChanged. Notifications from INotifyCollectionChanged (e.g. ObserveableCollection<T>) aren't handled by default, but you can enabled that with BindingOperations.EnableCollectionSynchronization.
It is also very helpful if you can recompose your long-running task as sequences of awaitable, non-UI-interacting operations interleaved with the UI-interacting stuff. Then you can just use async/await to manage the cross-thread aspects. This approach is particularly important if you aren't using data binding (but if you aren't, you should be!).
Related
My following code is Implementing a custom WPF Command. I have bonded only the first button (titled Exit) with the CommandBinding so that when Exit button is clicked and e.CanExecute is true in CommandBinding_CanExecute event, the CommandBinding_Executed event closes the app. This scenario works fine with Exit button. But, when btnTest button - that is not bonded with any command - is clicked, CommandBinding_CanExecute event also gets called. This can be tested by placing a breakpoint on the btnTest_Click event and noticing that after the code exits this event the cursor goes to CommandBinding_CanExecute event.
Question: Why the btnTest button is also calling CommandBinding_CanExecute event despite that fact that CommandBinding is used only on Exit button. What I may be missing here, and how can we fix the issue?
Remarks For brevity I have simplified the issue. But in real scenario e.CanExecute value in CommandBinding_CanExecute is set to true by calling a function that performs a long complex logic that returns true or false based on certain scenario for the Exit button. And I don't want that long logic to be performed when other buttons (e.g. btnTest) is clicked.
MainWindow.Xaml:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Content="Exit" Command="local:CustomCommands.Exit">
<Button.CommandBindings>
<CommandBinding Command="local:CustomCommands.Exit" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed"/>
</Button.CommandBindings>
</Button>
<Button x:Name="btnTest" Content="Test" Click="btnTest_Click" Margin="10"/>
</StackPanel>
</Grid>
</Window>
MainWindow.Xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btnTest_Click(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Why this event is calling ExitCommand_CanExecute");
}
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
Application.Current.Shutdown();
}
}
public static class CustomCommands
{
public static readonly RoutedUICommand Exit = new RoutedUICommand
(
"Exit",
"Exit",
typeof(CustomCommands),
new InputGestureCollection()
{
new KeyGesture(Key.F4, ModifierKeys.Alt)
}
);
}
What makes you think btnTest is calling CommandBinding_CanExecute? It doesn't.
The CanExecute method of the command is called by the CommandManager whenever it wants to know the current status of the command. You don't control when this happens. The framework does. It's not connected to the btnTest.
If you have some complex logic in CanExecute, you should consider creating a custom command class that implements the ICommand interface and raise the CanExecuteChanged event whenever you want the framework to refresh the status of the command by calling its CanExecute method. This way you can control when the command should be refreshed.
You could then bind the Command property of the Button to an instance of your custom command class. If you google for "DelegateCommand" or "RelayCommand", you should find a lot of examples. This blog post may be a good starting point.
Any interaction with the UI which is considered by the designers of wpf to be significant will indirectly initiate a check of all bound canexecute.
The idea being you changed something, did something or other. Best check if all these commands should still be enabled.
It's actually commandmanager.requerysuggested() that is invoked.
This doesn't directly invoke canexecute.
What it does is tells commands they should go check whether they can still be executed.
This isn't completely insane because whilst your button's command is invoking some code then there's a fair chance if the user clicks some other button then your viewmodel will be partly updated or in some indeterminate state,
You should never drive other logic using canexecute.
It is very common to add a bool IsBusy to a base viewmodel and check that to see if anything is doing stuff and you should not allow the user to do something else.
An extra check within commands on IsBusy is part of this pattern.
I have a wpf application which does very heavy actions in which the user needs to wait while the application "thinks".
What I want to do is, while the main thread of the application is thinking, another thread will disable the whole window and give it kind of a grayish color and a circular progress bar will appear in the middle of the screen.
It's kind of a big question and I don't really need the whole code to do this just the general Idea.
Thanks for all your help..
In addition to the above suggestions (Background worker, Dispatcher) - yes these are the correct techniques to get what you want, but let me discuss the UI effect you requested in your question. If you are using the MVVM pattern, you can create some "I'm busy" UI and bind to an IsBusy property in the view model to show and hide the UI. For instance:
public class MyViewModel : INotifyPropertyChanged
{
// Bind to this property any UI you want to
// show/hide during long running updates
public bool IsBusy
{
get { return _isBusy; }
set
{
_isBusy = true;
OnPropertyChanged("IsBusy");
}
}
private void OnPropertyChanged(string prop)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(prop));
}
}
// Note: This is intended to be called on a background thread
private void DoLongRunningOperationOnABackgroundThread()
{
try
{
IsBusy = true;
// do your work
}
finally
{
IsBusy = false;
}
}
}
Then in the UI use this xaml (or similar)
<UserControl:MyControl x:Class="MyApp.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="boolToVis"/>
</UserControl.Resources>
<Grid>
<!-- your UI code goes here -->
<!-- Below this, at higher Z-Order place a control to gray out the screen when IsBusy = true -->
<Border Background="#55000000" BorderThickness="0" Visibility="{Binding IsBusy, Converter={StaticResource boolToVis}}">
<TextBlock Text="I AM BUSY!" Font-Size="32" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White"/>
</Border>
<Grid>
</UserControl>
The net effect will be when you use a background worker or threadpool to call the DoLongRunningOperation function in your viewmodel, the border defined in Xaml will show/hide as the operation starts/stops. You won't need the dispatcher to invoke here either as WPF handles the thread marshalling for you.
There are implementations of busy controls with whirlygig animations etc... on the net too to spice up the UI.
Best regards,
Use Dispatcher.BeginInvoke to change the Enable-Property of the UI components and show/hide the progressbar out of the worker thread
for the worker-thread you can use the BackgroundWorker-Class
Offload the heavy action to a new thread and do the UI stuff (disable, gray out and progress bar) on the main thread. See BackgroundWorker and Dispatcher.
Using a new thread for the UI stuff is possible, but not using the existing Window. A UI control (Dispatcher) can online be used/called by the thread it belongs to. You could however create a new thread and use a new Window with a new Dispatcher to do the UI stuff. You would then have to position the new Window over the original. Not as easy as my first suggestion. It might be an option if you don't know when the heavy action is executed. See here, here and here.
Take a look at this sample:
public void DoHeavyWork()
{
mainDispatcher = Dispatcher.CurrentDispatcher;
DisableWindow();
workDelegate.BeginInvoke(EnableWindowCallBack, null);
}
private void EnableWindowCallBack(IAsyncResult asyncResult)
{
workDelegate.EndInvoke(asyncResult);
mainDispatcher.InvokeIfRequired(() => { EnableWindow(); });
}
When you call DoHeavyWork i assume we are on the thread that has access to the UI, which should be the usual. DisableWindow shows the animation or whatever should be shown while working. Then you invoke your predefined delegate, workDelegate which will run on a new thread, and when it's done, the callback should restore the view.
Note that the call to EnableWindow has to be made on the thread that has access to the UI.
I have a memory leak in a silverlight app, I used this information to get started,
http://blogs.msdn.com/b/slperf/archive/2010/08/19/analyzing-silverlight-memory-usage-part-1-obtaining-measurements.aspx
Which was excellent. I have extracted some of my code to break down the issue. So the code looks like this, a child window,
<controls:ChildWindow x:Class="MemoryLeakTesting2.ConfirmDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
xmlns:telerik="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls"
Width="375" >
<Grid Margin="2">
<telerik:RadButton Content="OK" Click="OnClick" Command="{Binding CancelActionCommand}" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1" />
</Grid>
</controls:ChildWindow>
The code behind is this,
public partial class ConfirmDialog : ChildWindow
{
public ConfirmDialog()
{
InitializeComponent();
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
private void OnClick(object sender, RoutedEventArgs e)
{
DialogResult = true;
}
}
I am calling this code from the button click event in my main silverlight page like this,
private void Button_Click(object sender, RoutedEventArgs e)
{
ConfirmDialog dialog = new ConfirmDialog();
dialog.Show();
}
This leaks memory every time I open the popup and close it. I use WinDbg and it actually shows that the ConfirmDialog instance is not freed after each time it is popped up and closed??
The Button.Command is notorious for leaking. My guess is that the value CancelActionCommand has a reference to a long lived object. The Button won't unhook from the ICommand.CanExecuteChanged event. You should consider using a Weak Event Pattern to limit your leakable surface area.
Here is a better explanation and example code to fix the problem.
Could it be:
On every click event you are creating ConfirmDialog object, which might hang around after it is no longer being used. Can you create that as a class variable and only have one reference and use that instead when you need to show the ChildWindow
I'm creating a standard menu in my WPF application.
I know that I can create custom commands, but I know there are also a bunch of standard commands to bind to.
For example, to open a file I should bind to ApplicationCommands.Open, to close a file I should bind to ApplicationCommands.Close. There's also a large number of EditCommands, ComponentCommands or NavigationCommands.
There doesn't seem to be an "Exit" command. I would have expected there to be ApplicationCommands.Exit.
What should I bind to the "Exit" menu item? To create a custom command for something this generic just seems wrong.
Unfortunately, there is no predefined ApplicationCommands.Exit. Adding one to WPF was suggested on Microsoft Connect in 2008: http://connect.microsoft.com/VisualStudio/feedback/details/354300/add-predefined-wpf-command-applicationcommands-exit. The item has been marked closed/postponed, however.
Mike Taulty discussed how to create your own Exit command in an article on his blog.
AFAIK there's no ApplicationCommands.Quit or ApplicationCommands.Exit, so I guess you're gonna have to create it yourself...
Anyway, if you're using the MVVM pattern, RoutedCommands are not exactly handy, so it's better to use a lightweight alternative like RelayCommand or DelegateCommand.
Not that complex actually (but still, M$ sucks for not providing it). Here you go:
public static class MyCommands
{
private static readonly ICommand appCloseCmd = new ApplicationCloseCommand();
public static ICommand ApplicationCloseCommand
{
get { return appCloseCmd; }
}
}
//===================================================================================================
public class ApplicationCloseCommand : ICommand
{
public event EventHandler CanExecuteChanged
{
// You may not need a body here at all...
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return Application.Current != null && Application.Current.MainWindow != null;
}
public void Execute(object parameter)
{
Application.Current.MainWindow.Close();
}
}
And the body of the AplicationCloseCommand.CanExecuteChanged event handler may not be even needed.
You use it like so:
<MenuItem Header="{DynamicResource MenuFileExit}" Command="MyNamespace:MyCommands.ApplicationCloseCommand"/>
Cheers!
(You cannot imagine how long it took me to discover this Command stuff myself...)
Yes, it would've made a lot of sense for Microsoft to include an ApplicationCommands.Exit command in their collection of pre-defined commands. It disappoints me that they didn't. But as the answers to this question demonstrate, not all is lost.
There are lots of workarounds possible for the lack of a proper ApplicationCommands.Exit object. However, I feel most miss the point. Either they implement something in the view model, for something that really is strictly a view behavior (in some cases reaching into the view object graph with e.g. Application.Current.MainWindow!), or they write a bunch of code-behind to do what XAML does very well and much more conveniently.
IMHO, the simplest approach is just to declare a RoutedUICommand resource for the window, attach that to a command binding, and to a menu item, to hook all the parts up. For example:
<Window x:Class="ConwaysGameOfLife.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<RoutedUICommand x:Key="fileExitCommand" Text="File E_xit">
<RoutedUICommand.InputGestures>
<KeyGesture >Alt+F4</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
</Window.Resources>
<Window.CommandBindings>
<CommandBinding Command="{StaticResource fileExitCommand}" Executed="fileExitCommand_Executed"/>
</Window.CommandBindings>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<!-- other menu items go here -->
<Separator/>
<MenuItem Command="{StaticResource fileExitCommand}"/>
</MenuItem>
</Menu>
<!-- the main client area UI goes here -->
</DockPanel>
</Window>
The Executed event handler for the command binding is trivial:
private void fileExitCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
Close();
}
Assuming, of course, your program implementation follows the usual semantics of closing the main window to exit the program.
In this way, all of the UI-specific elements go right into the RoutedUICommand object, which can be configured correctly and conveniently right in the XAML rather than having to declare a new C# class to implement the command and/or mess around with the input bindings from code-behind. The MenuItem object already knows what to do with a RoutedUICommand in terms of display, so going this route provides a nice decoupling of the command's properties from the rest of the UI. It also provides a convenient way to provide a secondary key gesture, in case you'd prefer something other than the default Alt+F4 (e.g. Ctrl+W).
You can even put the RoutedUICommand declaration in the App.xaml file, for reuse among multiple windows in your program, should they exist. Again, decoupling the UI-specific aspects, which are declared in the resource, from the consumers that are found throughout the program.
I find this approach much more generalizable and easily implemented than the other options which I've seen presented (here and elsewhere).
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
Pretty simple to do:
using System.Windows.Input;
namespace YourApp
{
static class ApplicationCommands
{
public static RoutedCommand Quit { get; }
static ApplicationCommands()
{
var inputGestures = new InputGestureCollection();
inputGestures.Add(new KeyGesture(Key.Q, ModifierKeys.Control));
Quit = new RoutedUICommand("Quit", "Quit", typeof(ApplicationCommands),
inputGestures);
}
}
}
Use it in your XAML like this:
<Window.CommandBindings>
<CommandBinding Command="local:ApplicationCommands.Quit"
Executed="QuitCommandOnExecuted"/>
</Window.CommandBindings>
[..]
<MenuItem Command="local:ApplicationCommands.Quit" />
Code-behind:
void QuitCommandOnExecuted(object sender, ExecutedRoutedEventArgs e)
{
Application.Current.Shutdown();
}
You can modify the Text property of a command before you bind it in a window. This will change the text of the command everywhere it appears in your ui.
EDIT: Do this to Close in the Window or App ctor
The easiest way is to implement ButtonClick event handler and invoke Window.Close() method, but how doing this through a Command binding?
All it takes is a bit of XAML...
<Window x:Class="WCSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Close"
Executed="CloseCommandHandler"/>
</Window.CommandBindings>
<StackPanel Name="MainStackPanel">
<Button Command="ApplicationCommands.Close"
Content="Close Window" />
</StackPanel>
</Window>
And a bit of C#...
private void CloseCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
this.Close();
}
(adapted from this MSDN article)
Actually, it is possible without C# code. The key is to use interactions:
<Button Content="Close">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:CallMethodAction TargetObject="{Binding ElementName=window}" MethodName="Close"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
In order for this to work, just set the x:Name of your window to "window", and add these two namespaces:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
This requires that you add the Expression Blend SDK DLL to your project, specifically Microsoft.Expression.Interactions.
In case you don't have Blend, the SDK can be downloaded here.
I think that in real world scenarios a simple click handler is probably better than over-complicated command-based systems but you can do something like that:
using RelayCommand from this article http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
public class MyCommands
{
public static readonly ICommand CloseCommand =
new RelayCommand( o => ((Window)o).Close() );
}
<Button Content="Close Window"
Command="{X:Static local:MyCommands.CloseCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}}"/>
If the window was shown with Window.ShowDialog():
The simplest solution that I know of is to set the IsCancel property to true of the close Button:
<Button Content="Close" IsCancel="True" />
No bindings needed, WPF will do that for you automatically!
This properties provide an easy way of saying these are the "OK" and "Cancel" buttons on a dialog. It also binds the ESC key to the button.
Reference: MSDN Button.IsCancel property.
For .NET 4.5 SystemCommands class will do the trick (.NET 4.0 users can use WPF Shell Extension google - Microsoft.Windows.Shell or Nicholas Solution).
<Window.CommandBindings>
<CommandBinding Command="{x:Static SystemCommands.CloseWindowCommand}"
CanExecute="CloseWindow_CanExec"
Executed="CloseWindow_Exec" />
</Window.CommandBindings>
<!-- Binding Close Command to the button control -->
<Button ToolTip="Close Window" Content="Close" Command="{x:Static SystemCommands.CloseWindowCommand}"/>
In the Code Behind you can implement the handlers like this:
private void CloseWindow_CanExec(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void CloseWindow_Exec(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.CloseWindow(this);
}
In the beginning I was also having a bit of trouble figuring out how this works so I wanted to post a better explanation of what is actually going on.
According to my research the best way to handle things like this is using the Command Bindings. What happens is a "Message" is broadcast to everything in the program. So what you have to do is use the CommandBinding. What this essentially does is say "When you hear this Message do this".
So in the Question the User is trying to Close the Window. The first thing we need to do is setup our Functions that will be called when the SystemCommand.CloseWindowCommand is broadcast. Optionally you can assign a Function that determines if the Command should be executed. An example would be closing a Form and checking if the User has saved.
MainWindow.xaml.cs (Or other Code-Behind)
void CloseApp( object target, ExecutedRoutedEventArgs e ) {
/*** Code to check for State before Closing ***/
this.Close();
}
void CloseAppCanExecute( object sender, CanExecuteRoutedEventArgs e ) {
/*** Logic to Determine if it is safe to Close the Window ***/
e.CanExecute = true;
}
Now we need to setup the "Connection" between the SystemCommands.CloseWindowCommand and the CloseApp and CloseAppCanExecute
MainWindow.xaml (Or anything that implements CommandBindings)
<Window.CommandBindings>
<CommandBinding Command="SystemCommands.CloseWindowCommand"
Executed="CloseApp"
CanExecute="CloseAppCanExecute"/>
</Window.CommandBindings>
You can omit the CanExecute if you know that the Command should be able to always be executed Save might be a good example depending on the Application. Here is a Example:
<Window.CommandBindings>
<CommandBinding Command="SystemCommands.CloseWindowCommand"
Executed="CloseApp"/>
</Window.CommandBindings>
Finally you need to tell the UIElement to send out the CloseWindowCommand.
<Button Command="SystemCommands.CloseWindowCommand">
Its actually a very simple thing to do, just setup the link between the Command and the actual Function to Execute then tell the Control to send out the Command to the rest of your program saying "Ok everyone run your Functions for the Command CloseWindowCommand".
This is actually a very nice way of handing this because, you can reuse the Executed Function all over without having a wrapper like you would with say WinForms (using a ClickEvent and calling a function within the Event Function) like:
protected override void OnClick(EventArgs e){
/*** Function to Execute ***/
}
In WPF you attach the Function to a Command and tell the UIElement to execute the Function attached to the Command instead.
I hope this clears things up...
One option that I've found to work is to set this function up as a Behavior.
The Behavior:
public class WindowCloseBehavior : Behavior<Window>
{
public bool Close
{
get { return (bool) GetValue(CloseTriggerProperty); }
set { SetValue(CloseTriggerProperty, value); }
}
public static readonly DependencyProperty CloseTriggerProperty =
DependencyProperty.Register("Close", typeof(bool), typeof(WindowCloseBehavior),
new PropertyMetadata(false, OnCloseTriggerChanged));
private static void OnCloseTriggerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = d as WindowCloseBehavior;
if (behavior != null)
{
behavior.OnCloseTriggerChanged();
}
}
private void OnCloseTriggerChanged()
{
// when closetrigger is true, close the window
if (this.Close)
{
this.AssociatedObject.Close();
}
}
}
On the XAML Window, you set up a reference to it and bind the Behavior's Close property to a Boolean "Close" property on your ViewModel:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<i:Interaction.Behaviors>
<behavior:WindowCloseBehavior Close="{Binding Close}" />
</i:Interaction.Behaviors>
So, from the View assign an ICommand to change the Close property on the ViewModel which is bound to the Behavior's Close property. When the PropertyChanged event is fired the Behavior fires the OnCloseTriggerChanged event and closes the AssociatedObject... which is the Window.