Reputation: 2810
I'm trying to set up some behaviors to control windows in an MVVM application.
My thought is behaviors can be set decoratively in XAML and exist in their own class, allowing for them in some cases to be reused in many different views.
I also have a menu item that is bound to a RelayCommand. Both of these work fine on their own, however when I try to combine the two things don't work as expected:
MainView.xaml
<Window x:Class="CaseManager.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:VM="clr-namespace:CaseManager.ViewModels;assembly=CaseManager.ViewModels"
xmlns:local="clr-namespace:CaseManager.Views"
local:ExitBehavior.ExitWhen="{Binding ExitFlag}"
Title="Main Window" Height="350" Width="525">
<Window.DataContext>
<VM:MainViewModel />
</Window.DataContext>
<Grid>
<Menu Height="20" VerticalAlignment="Top">
<MenuItem Header="_File">
<MenuItem Header="_Exit" Command="{Binding ExitCommand}" />
</MenuItem>
</Menu>
</Grid>
</Window>
MainViewModel.cs
namespace CaseManager.ViewModels
{
using System;
using System.Collections.Generic;
using Commands;
public class MainViewModel : ViewModelBase
{
# region RelayCommands
private RelayCommand _exitCommand;
public RelayCommand ExitCommand
{
get { return _exitCommand; }
private set { _exitCommand = value; }
}
#endregion
private bool _exitFlag;
public bool ExitFlag {
get { return _exitFlag; }
private set { _exitFlag = value; }
}
public MainViewModel()
{
ExitCommand = new RelayCommand(ExitCommand_Execute);
ExitFlag = false;
}
private void ExitCommand_Execute(object obj)
{
System.Console.WriteLine("Command executed");
ExitFlag = true;
}
}
}
ExitCommand.cs
namespace CaseManager.Views
{
using System;
using System.Windows;
public static class ExitBehavior
{
public static bool GetExitWhen(DependencyObject obj)
{
return (bool)obj.GetValue(ExitWhenProperty);
}
public static void SetExitWhen(DependencyObject obj, bool value)
{
obj.SetValue(ExitWhenProperty, value);
}
public static readonly DependencyProperty ExitWhenProperty =
DependencyProperty.RegisterAttached(
"ExitWhen", typeof(bool), typeof(ExitBehavior),
new UIPropertyMetadata(OnExitWhenChanged));
static void OnExitWhenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
System.Console.WriteLine("Behavior executed");
Environment.Exit(0);
}
}
}
Running the code above as is will output 'Command executed' in the console when I select exit in the menu. So I know the relay command is working fine. However the behavior is not.
If I change the constructor of my MainViewModel
to set ExitFlag
to true, the program will launch, print 'Behavior executed' to console, and then quit.
Both the ExitBehavior and RelayCommand work on their own, however when I try to trigger the ExitBehavior by setting the ExitFlag in my relay command, they cannot be used together. Am i missing something here?
For brevity here is RelayCommand.cs
:
namespace CaseManager.Commands
{
using System;
using System.Windows.Input;
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion
#region Constructors
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion
#region ICommand Members
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion
}
}
Upvotes: 0
Views: 397
Reputation: 22702
Firtsly, as I understood from your code, here:
local:CloseBehavior.CloseWhen="{Binding CloseFlag}"
there must be a property ExitFlag
.
Secondly, this property should call OnPropertyChanged
method from INotifyPropertyChanged
interface to update the property and in XAML should be as:
local:CloseBehavior.CloseWhen="{Binding Path=ExitFlag, Mode=TwoWay}"
Upvotes: 0
Reputation: 37790
You have to notify the binding engine, that your property ExitFlag
was changed. Assuming, that ViewModelBase
implements INotifyPropertyChanged
somehow:
public bool ExitFlag
{
get { return _exitFlag; }
private set
{
_exitFlag = value;
OnPropertyChanged("ExitFlag");
}
}
where OnPropertyChanged
is a method, that raises INPC.PropertyChanged
event.
Upvotes: 3