WPF MouseLeave not firing binding by command - wpf

I started the MVVM project and set the View binding all events on the TextBlock from ViewModel. I have set 3 commands (MouseEnter, MouseLeave, and MouseDown). But only MouseEnter and MouseDown are firing, MouseLeave event not firing
This is the view
<Window x:Class="SilentUpdate.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:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:local="clr-namespace:SilentUpdate"
xmlns:res="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Background="Gainsboro"
WindowStartupLocation="CenterScreen" WindowStyle="None"
Title="" Height="600" Width="1024">
<Grid>
<Grid.Resources>
<ResourceDictionary>
<Style TargetType="TextBlock" x:Key="IconText">
<Setter Property="FontSize" Value="32"/>
<Setter Property="Foreground" Value="#ADADAD"/>
<Setter Property="FontFamily" Value="pack://application:,,,/Resources/#Segoe UI Symbol"/>
<Setter Property="Margin" Value="10,10,10,10"/>
</Style>
<res:String x:Key="homeIcon"></res:String>
<res:String x:Key="settingsIcon"></res:String>
<res:String x:Key="previewIcon"></res:String>
<res:String x:Key="runIcon"></res:String>
<res:String x:Key="saveIcon"></res:String>
<res:String x:Key="exitIcon"></res:String>
<res:String x:Key="warningIcon"></res:String>
<res:String x:Key="folderIcon"></res:String>
</ResourceDictionary>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel x:Name="Navibar" Orientation="Vertical" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Background="#0096C1">
<TextBlock Name="home"
Foreground="{Binding HomeColor}"
Text="{StaticResource homeIcon}"
Style="{StaticResource IconText}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding EventMouseOver}"
CommandParameter="{Binding ElementName=home}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding MouseLeaveButton}"
CommandParameter="{Binding ElementName=home}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding HomeCommand}"
CommandParameter="{Binding ElementName=home}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
<TextBlock Name="settings"
Text="{StaticResource settingsIcon}"
Style="{StaticResource IconText}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding EventMouseOver}"
CommandParameter="{Binding ElementName=settings}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding MouseLeaveButton}"
CommandParameter="{Binding ElementName=settings}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding SettingCommand}"
CommandParameter="{Binding ElementName=settings}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
<TextBlock Name="preview"
IsEnabled="{Binding PreviewStatus, Mode=OneWay}"
Text="{StaticResource previewIcon}"
Style="{StaticResource IconText}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding EventMouseOver}"
CommandParameter="{Binding ElementName=preview}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding MouseLeaveButton}"
CommandParameter="{Binding ElementName=preview}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding PreviewCommand}"
CommandParameter="{Binding ElementName=preview}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
<TextBlock Name="run"
IsEnabled="{Binding RunStatus, Mode=OneWay}"
Text="{StaticResource runIcon}"
Style="{StaticResource IconText}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding EventMouseOver}"
CommandParameter="{Binding ElementName=run}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding MouseLeaveButton}"
CommandParameter="{Binding ElementName=run}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding RunCommand}"
CommandParameter="{Binding ElementName=run}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
<TextBlock Name="save"
IsEnabled="{Binding SaveStatus, Mode=OneWay}"
Text="{StaticResource saveIcon}"
Style="{StaticResource IconText}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding EventMouseOver}"
CommandParameter="{Binding ElementName=save}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding MouseLeaveButton}"
CommandParameter="{Binding ElementName=save}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding SaveCommand}"
CommandParameter="{Binding ElementName=save}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
<TextBlock Name="exit"
Text="{StaticResource exitIcon}"
Style="{StaticResource IconText}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding EventMouseOver}"
CommandParameter="{Binding ElementName=exit}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding MouseLeaveButton}"
CommandParameter="{Binding ElementName=exit}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding ExitButtonCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</StackPanel>
</Grid>
</Window>
And this is the ViewModel
using SilentUpdate.Helpers;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace SilentUpdate.ViewModels
{
public class MainViewModel : INotifyPropertyChanged
{
#region Property change interface implement
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseProperChanged (string prop)
{
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(prop));
}
}
#endregion
#region Button Status
// To keep track the active click button
private TextBlock activeButton;
private Brush homeColor;
private bool previewStatus, runStatus, saveStatus;
public Brush HomeColor
{
get { return this.homeColor; }
set { this.homeColor = value; RaiseProperChanged("HomeColor"); }
}
public bool PreviewStatus
{
get { return this.previewStatus; }
set
{
this.previewStatus = value;
RaiseProperChanged("PreviewStatus");
}
}
public bool RunStatus
{
get { return this.runStatus; }
set
{
this.runStatus = value;
RaiseProperChanged("RunStatus");
}
}
public bool SaveStatus
{
get { return this.saveStatus; }
set
{
this.saveStatus = value;
RaiseProperChanged("SaveStatus");
}
}
#endregion
#region Event Binding
// Command for binding to the event
private ICommand exitButtonCommand, eventMouseOver, eventMouseLeave;
private ICommand homeCommand, settingCommand, previewCommand, runCommand, saveCommand;
private bool canExecute = true;
public bool CanExecute
{
get { return this.canExecute; }
set
{
if (this.canExecute == value)
{
return;
}
this.canExecute = value;
}
}
/// <summary>
/// Public for binding to Exit button
/// </summary>
public ICommand ExitButtonCommand
{
get { return this.exitButtonCommand; }
set
{
this.exitButtonCommand = value;
}
}
/// <summary>
/// Exit the application when Exit button click binding to ExitButtonCommand
/// </summary>
/// <param name="obj"></param>
public void ExitApp(object obj)
{
Application.Current.Shutdown();
}
/// <summary>
/// Public for binding to Home button
/// </summary>
public ICommand HomeCommand
{
get { return this.homeCommand; }
set
{
this.homeCommand = value;
}
}
/// <summary>
/// Actual home event, will display the home page
/// This will update the page binding variable
/// </summary>
/// <param name="obj"></param>
public void HomeEvent (object obj)
{
// Change the active button
ChangeActive((TextBlock)obj);
// Change the button status
PreviewStatus = false;
RunStatus = false;
SaveStatus = false;
HomeColor = new SolidColorBrush(Colors.White);
MessageBox.Show("HomeEvent");
}
/// <summary>
/// Public for binding to Setting button
/// </summary>
public ICommand SettingCommand
{
get { return this.settingCommand; }
set
{
this.settingCommand = value;
}
}
/// <summary>
/// Actual Setting event, will display the setting page
/// This will update the page binding variable
/// </summary>
/// <param name="obj"></param>
public void SettingEvent(object obj)
{
// Change the active button
ChangeActive((TextBlock)obj);
// Change the button status
PreviewStatus = true;
RunStatus = false;
SaveStatus = false;
MessageBox.Show("SettingEvent");
}
/// <summary>
/// Public for binding to Preview button
/// </summary>
public ICommand PreviewCommand
{
get { return this.previewCommand; }
set
{
this.previewCommand = value;
}
}
/// <summary>
/// Actual Preview event, will display the preview page
/// based on the Messenger sending to the page for the environment
/// setting by the setting page
/// This will update the page binding variable
/// </summary>
/// <param name="obj"></param>
public void PreviewEvent(object obj)
{
// Change the active button
ChangeActive((TextBlock)obj);
// Change the button status
PreviewStatus = true;
RunStatus = true;
SaveStatus = false;
MessageBox.Show("PreviewEvent");
}
/// <summary>
/// Public for binding to Run button
/// </summary>
public ICommand RunCommand
{
get { return this.runCommand; }
set
{
this.runCommand = value;
}
}
/// <summary>
/// Actual Preview event, will display the after run page
/// based on the Messenger sending to the page for the environment
/// setting by the setting page and the selection of the list file
/// from the Preview page
/// This will update the page binding variable
/// </summary>
/// <param name="obj"></param>
public void RunEvent(object obj)
{
// Change the active button
ChangeActive((TextBlock)obj);
// Change the button status
PreviewStatus = true;
RunStatus = true;
SaveStatus = true;
MessageBox.Show("RunEvent");
}
/// <summary>
/// Public for binding to Save button
/// </summary>
public ICommand SaveCommand
{
get { return this.saveCommand; }
set
{
this.saveCommand = value;
}
}
/// <summary>
/// Actual Save event, will generate the PDF file log
/// And launch the PDF file based on default application setting
/// </summary>
/// <param name="obj"></param>
public void SaveEvent(object obj)
{
ChangeActive((TextBlock)obj);
MessageBox.Show("SaveEvent");
}
/// <summary>
/// This event uses by all button to change color to active state
/// </summary>
public ICommand EventMouseOver
{
get { return this.eventMouseOver; }
set
{
this.eventMouseOver = value;
}
}
/// <summary>
/// Actual mouse enter event for binding command EventMouseOver
/// </summary>
/// <param name="obj">The target object of button</param>
public void MouseOverButton(object obj)
{
// Casting the object
TextBlock target = (TextBlock)obj;
if (activeButton == null)
{
// High light target
activeButton = target;
}
// High light target
HighLightText(target, true);
}
/// <summary>
/// This event uses by all button to change color to inactive state
/// </summary>
public ICommand EventMouseLeave
{
get { return this.eventMouseLeave; }
set { this.eventMouseLeave = value; }
}
/// <summary>
/// Actual mouse leave event for binding command EventMouseLeave
/// </summary>
/// <param name="obj">The target object of button</param>
private void MouseLeaveButton(object obj)
{
// Casting the object
TextBlock target = (TextBlock)obj;
if (target.Equals(activeButton) == false)
{
HighLightText(target, false);
}
HighLightText(activeButton, true);
}
/// <summary>
/// Update the canExecute property
/// </summary>
/// <param name="obj"></param>
public void ChangeCanExecute(object obj)
{
canExecute = !canExecute;
}
#endregion
#region Constructor
public MainViewModel()
{
exitButtonCommand = new RelayCommand(ExitApp, Param => this.canExecute);
eventMouseOver = new RelayCommand(MouseOverButton);
eventMouseLeave = new RelayCommand(MouseLeaveButton);
homeCommand = new RelayCommand(HomeEvent);
settingCommand = new RelayCommand(SettingEvent);
previewCommand = new RelayCommand(PreviewEvent);
runCommand = new RelayCommand(RunEvent);
saveCommand = new RelayCommand(SaveEvent);
// Set the Preview status disable when start
PreviewStatus = false;
// Set the Run status disable when start
RunStatus = false;
// Set the Save status disable when start
SaveStatus = false;
// HomeColor
HomeColor = new SolidColorBrush(Colors.White);
}
#endregion
#region Private Helper
private void HighLightText(TextBlock target, bool isHighlight)
{
if (isHighlight)
{
target.Foreground = new SolidColorBrush(Colors.White);
}
else
{
target.Foreground = new SolidColorBrush(System.Windows.Media.Color.FromArgb(68, 173, 173, 173));
}
}
private void ChangeActive (TextBlock target)
{
if (activeButton != null)
{
HighLightText(activeButton, false);
}
activeButton = target;
HighLightText(activeButton, true);
activeButton.ReleaseMouseCapture();
target.ReleaseMouseCapture();
HomeColor = new SolidColorBrush(System.Windows.Media.Color.FromArgb(68, 173, 173, 173));
}
#endregion
}
}

My mistake for the implementation, I should leave the UI logic in view not viewmodel. That solves the issue

Related

WPF: bind my CheckBox into my commnd pure XAML

I try to bind my CheckBox into my commnd.
Base view model
public ViewModelBase()
{
SelectedFileCommand = new SelectedFileCommand(this);
}
<Page.DataContext>
<viewmodel:ViewModelBase/>
</Page.DataContext>
Command
public class SelectedFileCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public ViewModelBase ViewModel { get; set; }
public SelectedFileCommand(ViewModelBase viewModel)
{
ViewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
}
}
}
My CheckBox
<CheckBox IsChecked="{Binding IsSelected}"
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding SelectedFileCommand}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
I also Try:
<CheckBox DataContext="{Binding}"
<i:Interaction.Triggers>
<i:EventTrigger EventName="IsChecked">
<i:InvokeCommandAction Command="{Binding SelectedFileCommand}"
CommandParameter="CheckBox.IsChecked"/>
</i:EventTrigger>
</i:Interaction.Triggers>
But my Execute function not called.
EDIT
I forgot to mention that this CheckBox is inside ListViewItem
Working solution
<CheckBox IsChecked="{Binding IsSelected}"
Command="{Binding DataContext.CheckBoxSelectedFileCommand, ElementName=mainView}"
CommandParameter="{Binding IsChecked}"/>
If the checkbox is in a listview when you say Command="{Binding SelectedFileCommand}" you will bind to the listview item's datacontext. If yor command is in the viewmodel of your window this won't work. Something like this will bind to the command that is in your main viewmodel.
Command="{Binding DataContext.SelectedFileCommand, ElementName=mainView}"
Here I gave the window x:Name=mainView. This way I can bind to properties of it's dataContext.
And, IsChecked is not an event you should use "Checked".
Last, the command parameter issue. Since there are two different events for checkbox (Checked/Unchecked) you can use two commands and not pass any parameters. Or you can put a property in the list item viewmodel like;
public bool IsChecked { get; set; }
and you can bind your checkbox's IsChecked property to this property. And finally you can bind command parameter to this new property.
Edit: Full example
<Window x:Class="WpfApp2.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:i="http://schemas.microsoft.com/expression/2010/interactivity"
x:Name="mainView"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ListView ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Text}" IsChecked="{Binding IsChecked}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding DataContext.SelectedFileCommand, ElementName=mainView}"
CommandParameter="{Binding IsChecked}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
Codebehind:
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
namespace WpfApp2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
}
public class MainViewModel
{
public ObservableCollection<ItemViewModel> Items { get; set; } = new ObservableCollection<ItemViewModel>();
public ICommand SelectedFileCommand { get; set; }
public MainViewModel()
{
SelectedFileCommand = new SelectedFileCommand(this);
this.Items.Add(new ItemViewModel() { Text = "Item 1" });
this.Items.Add(new ItemViewModel() { Text = "Item 2" });
this.Items.Add(new ItemViewModel() { Text = "Item 3" });
this.Items.Add(new ItemViewModel() { Text = "Item 4" });
}
}
public class ItemViewModel
{
public string Text { get; set; }
public bool IsChecked { get; set; }
}
public class SelectedFileCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public MainViewModel ViewModel { get; set; }
public SelectedFileCommand(MainViewModel viewModel)
{
ViewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
var x = parameter;
}
}
}

Unable to fire TreeView properties events

I am having problem with the following code. I have a TreeView Control which is bound to a Collection. The TreeView does get populated with the desired results. HOwever the "IsSelected" property and ContextMenu's click Command is not firing. Following is the XAML code.
<UserControl x:Class="Plan.Views.PadView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:v="clr-namespace:Planner.Views"
xmlns:vm="clr-namespace:Planner.ViewModels"
<Grid>
<StackPanel Orientation="Vertical">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" OpacityMask="#FFECF5F5">
<TreeView ItemsSource="{Binding Pads}" Name="tree_View" Width="190">
<TreeView.ItemContainerStyle >
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding WellPadViewModel.IsSelected}" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Rename" Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeView}}, Path=DataContext.RenameCommand}" />
</ContextMenu>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle >
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Members}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" >
<TextBlock.InputBindings>
<KeyBinding Key="F2" Command="{Binding RenameCommand}"/>
</TextBlock.InputBindings>
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</StackPanel>
</Grid>
</StackPanel>
</Grid>
</UserControl>
And here is my ViewModel
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
using System.ComponentModel;
using WPFApplication;
namespace FieldPlanner.ViewModels
{
public class PlanViewModel : BaseViewModel
{
Collection<Pads> pads = new Collection<Pads>();
public PlanViewModel()
{
IsSelected = true;
pads = new Collection<Pad>();
}
private ICommand _RenameCommand;
public ICommand RenameCommand
{
get
{
if (_RenameCommand == null)
{
_RenameCommand = new RelayCommand1((o) =>
{
// Your logic should go here
MessageBox.Show("Please rename me");
});
}
return _RenameCommand;
}
}
public ObservableCollection<PadInfo> Members { get; set; }
private static object _selectedItem = null;
// This is public get-only here but you could implement a public setter which also selects the item.
// Also this should be moved to an instance property on a VM for the whole tree, otherwise there will be conflicts for more than one tree.
public static object SelectedItem
{
get { return _selectedItem; }
private set
{
if (_selectedItem != value)
{
_selectedItem = value;
OnSelectedItemChanged();
}
}
}
public static void OnSelectedItemChanged()
{
// Raise event / do other things
}
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (_isSelected != value)
{
_isSelected = value;
OnPropertyChanged("IsSelected");
if (_isSelected)
{
SelectedItem = this;
}
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
/// <summary>
/// Class to hold the Pads info for a tree
/// </summary>
public class Pad
{
/// <summary>
/// Default Constructor
/// </summary>
public Pad()
{
this.Members = new ObservableCollection<PadInfo>();
}
/// <summary>
/// Name of the pad
/// </summary>
public string Name { get; set; }
/// <summary>
/// Members of the pad
/// </summary>
public ObservableCollection<PadInfo> Members { get; set; }
}
/// <summary>
/// Class to hold the well and slot IDs snapped to a pad
/// </summary>
public class PadInfo
{
/// <summary>
/// Slot ID
/// </summary>
public string SlotID { get; set; }
/// <summary>
/// Well ID
/// </summary>
public string WellID { get; set; }
}
public class RelayCommand1 : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
public RelayCommand1(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand1(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
// [DebuggerStepThrough]
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 // ICommand Members
}
}
How can I identify the issue?
You have two problems:
IsSelected:
<Setter Property="IsSelected" Value="{Binding WellPadViewModel.IsSelected}" />
In TreeViewItem DataContext is set to instance of Pad and Pad doesn't have property IsSelected You have to do sth like this:
<Setter Property="IsSelected" Value="{Binding DataContext.IsSelected, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}" />
Problem with ContextMenu is much more sirious. ContextMenu isn't in VisualTree so you cannot bind to RelativeSource. Solution is here WPF Relative source- Cannot find source for binding with reference
Best regards
Please set the Tag property in your DataTemplate to TreeViewItem. I have sth like this:
<DataTemplate>
<Grid Width="270" Height="20" Tag="{Binding DataContext, RelativeSource = {RelativeSource AncestorType={x:Type UserControl}}}">
...
<Grid.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Edit">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<command:EventToCommand Command="{Binding Tag.YOURCOMMAND}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
</ContextMenu>
</Grid.ContextMenu>
</Grid>
</DataTemplate>
It should work.

PropertyChanged event on viewmodel property

i'm trying to Raise a PropertyChanged event on a Property in my ViewModel
using interaction triggers .
CS :
public string MyContentProperty
{
get { return "I Was Raised From an outside Source !";}
}
XAML :
<Button Content="{Binding MyContentProperty}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Button.Click">
< .... what needs to be done ?>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
of course if there was any doubt for this question you have references to
xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
at your disposal , thanks in advance .
You can use a normal command or Expression Blend's CallMethodAction, InvokeCommandAction or ChangePropertyAction.
Here are four ways to do what you want:
<Button Content="Button" Height="23" Width="100" Command="{Binding RaiseItCmd}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding RaiseItCmd}"/>
<ei:CallMethodAction MethodName="RaiseIt" TargetObject="{Binding}"/>
<ei:ChangePropertyAction Value=""
PropertyName="MyContentProperty" TargetObject="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
Here I'm using MVVM Light's ViewModelBase:
using System.Windows.Input;
using GalaSoft.MvvmLight;
using Microsoft.Expression.Interactivity.Core;
public class ViewModel : ViewModelBase
{
public ViewModel()
{
RaiseItCmd = new ActionCommand(this.RaiseIt);
}
public string MyContentProperty
{
get
{
return "property";
}
set
{
this.RaiseIt();
}
}
public void RaiseIt()
{
RaisePropertyChanged("MyContentProperty");
}
public ICommand RaiseItCmd { get; private set; }
}

Executing a command on Checkbox.Checked or Unchecked

I have a checkbox control on a window. I'd like to execute a command that will call a method in the associated view model. I'll also need the value of the checkbox as well. I cannot seem to find a way to associate a command with a checkbox. Has anyone done this?
<CheckBox Content="CheckBox"
Command="{Binding YourCommand}"
CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Self}}" />
If you use MVVM, you can use event triggers like this:
<CheckBox IsChecked="{Binding ServiceOrderItemTask.IsCompleted, Mode=TwoWay}" Content="{Binding ServiceOption.Name}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding DataContext.IsCompletedCheckedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type t:RadGridView}}}" CommandParameter="{Binding}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding DataContext.IsCompletedUncheckedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type t:RadGridView}}}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
This will work what you requires -
<CheckBox CommandParameter="{Binding}"
Command="{Binding DataContext.AddRemovePresetAssignmentCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type UserControl}}}"
Content="{Binding Path=Name}">
Add System.Windows.Interactivity to your project references.
Add xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" to your XAML namespaces.
<CheckBox IsChecked="{Binding SomeBoolProperty, Mode=OneWay}" Content="Check Meee!">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding MyOnCheckedCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding MyOnUncheckedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
I implement INotifyPropertyChanged on my ViewModel as follows:
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
The SomeBoolProperty of my ViewModel then looks like this:
private bool _SomeBoolProperty = false;
public bool SomeBoolProperty {
get => _SomeBoolProperty;
set {
_SomeBoolProperty = value;
OnPropertyChanged(nameof(SomeBoolProperty));
}
}
I use RelayCommand as my command implementation from here
https://stackoverflow.com/a/22286816/336753.
The commands on my ViewModel then look like this:
public ICommand MyOnCheckedCommand { get; } = new RelayCommand(o => {
// Do something here.
SomeBoolProperty = true;
});
public ICommand MyOnUncheckedCommand { get; } = new RelayCommand(o => {
// Do something else here.
SomeBoolProperty = false;
});
I got to this question trying to find a way to reuse two commands I already had on my ViewModel. One called when checked and one when unchecked. I use them on some buttons too so did not want to add an extra parametrized command. People were asking here about ViewModel implementation so adding this answer to complete the one from Igor_S. Hope it helps.
I'm late... I used Rohit Vats answer and came up with this code.
The example is a working code extract and it is only here to help to understand every aspects. It is a pushpin that could be either active or inactive and it use a DelegateCommand. You could probably also use a RelayCommand or any other similar class to do the same job.
Command:
using System.Windows.Input;
namespace HQ.Wpf.Util.Command
{
public class StandardCommand
{
public static RoutedUICommand PinPropertyGrid = new RoutedUICommand("Pin property grid", "PinPropertyGrid", typeof(StandardCommand));
Xaml:
<CheckBox HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="2,0,3,0"
Command="{Binding CommandPinPropertyGrid}"
CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Self}}">
<CheckBox.Template>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Image x:Name="ImagePushpin" Width="16" Height="16" Source="pack://application:,,,/WpfUtil;component/Images/PushpinUnpinned16x16.png" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="ImagePushpin" Property="Source" Value="pack://application:,,,/WpfUtil;component/Images/PushpinPinned16x16.png" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</CheckBox.Template>
</CheckBox>
Model:
public MainWindowViewModel()
{
CommandPinPropertyGrid = new DelegateCommand<bool>(PinPropertyGrid);
...
// ******************************************************************
public DelegateCommand<bool> CommandPinPropertyGrid { get; private set; }
public void PinPropertyGrid(bool pinned)
{
this.IsPropertyGridPinned = pinned;
}
DelegateCommand:
using System;
using System.Windows.Input;
namespace HQ.Wpf.Util.Command
{
/// <summary>
/// Represents a command that forwards the <c>Execute</c> and <c>CanExecute</c> calls to specified delegates.
/// </summary>
public class DelegateCommand<T> : ICommand
{
private readonly Action<T> _executeCallback;
private readonly Predicate<T> _canExecuteCallback;
/////////////////////////////////////////////////////////////////////////////////////////////////////
// OBJECT
/////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Initializes a new instance of the <see cref="DelegateCommand<T>"/> class.
/// </summary>
/// <param name="executeCallback">The execute callback delegate.</param>
public DelegateCommand(Action<T> executeCallback)
: this(executeCallback, null)
{
// No-op
}
/// <summary>
/// Initializes a new instance of the <see cref="DelegateCommand<T>"/> class.
/// </summary>
/// <param name="executeCallback">The execute callback delegate.</param>
/// <param name="canExecuteCallback">The can execute callback delegate.</param>
public DelegateCommand(Action<T> executeCallback, Predicate<T> canExecuteCallback)
{
if (executeCallback == null)
throw new ArgumentNullException("executeCallback");
this._executeCallback = executeCallback;
this._canExecuteCallback = canExecuteCallback;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// INTERFACE IMPLEMENTATION
/////////////////////////////////////////////////////////////////////////////////////////////////////
#region ICommand Members
/// <summary>
/// Defines the method that determines whether the command can execute in its current state.
/// </summary>
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to <see langword="null"/>.</param>
/// <returns>
/// <c>true</c> if this command can be executed; otherwise, <c>false</c>.
/// </returns>
public bool CanExecute(object parameter)
{
return (this._canExecuteCallback == null) ? true : this._canExecuteCallback((T)parameter);
}
/// <summary>
/// Occurs when changes occur that affect whether or not the command should execute.
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (this._canExecuteCallback != null)
CommandManager.RequerySuggested += value;
}
remove
{
if (this._canExecuteCallback != null)
CommandManager.RequerySuggested -= value;
}
}
/// <summary>
/// Defines the method to be called when the command is invoked.
/// </summary>
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to <see langword="null"/>.</param>
public void Execute(object parameter)
{
this._executeCallback((T)parameter);
}
#endregion // ICommand Members
}
}
When you need only the Status of the CheckBox (Checked or Unchecked), then you don't need a Parameter. You can detect the Status of the Checkbox when you use this code:
CheckBox box = e.OriginalSource as CheckBox;
if(box.IsChecked.Value)
DoThis();
else
DoAnotherMethod();
"e" is the ExecutedRoutedEventArgs-Parameter in the Command. You Need box.IsChecked.Value, because box.IsChecked is from Type bool?.

TabItem header click

I have defined a control template/style for my tab items as follows:
<Style x:Key="TabItemStyle" TargetType="{x:Type TabItem}">
<Setter Property="Header" Value="{Binding Content.DataContext.Header, RelativeSource={RelativeSource Self}}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid Width="Auto" Height="Auto" x:Name="TabItemRoot" Margin="10,0,10,0">
<Button Command="{Binding Content.DataContext.HeaderClickedCommand}">
<ContentPresenter Margin="13,5,13,5"
x:Name="Content"
ContentSource="Header"
RecognizesAccessKey="True">
</ContentPresenter>
</Button>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When I click on the tab header the command bound to the button is called OK, however, the click event appears to have eaten the SelectionChanged event and therefore the tab page doesn't change.
Is there a better way to implement this so I can call a VM method and get still get the tab page to change?
Update as per comment
The idea being that if the user clicks the header of the currently active tab it updates the active tabs content through changes in the VM. Thanks
Here is my way to implement such functionality, but whether it is better or not - it's matter of taste.
The main xaml looks so:
<TabControl ItemsSource="{Binding TabItems}">
<TabControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Title}"/>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<local:ExecuteCommandAction Command="{Binding HeaderClickCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
There is no ControlTemplate, just DataTemplate with the attached property Interaction.Triggers, where the prefix i is defined in this string:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
This library can be found in MS Blend SDK or with the library mvvm light (on codeplex).
Also, don't confuse EventTriggers that has the prefix i and generic EventTriggers, they are different at some point, but I don't know exactly what the difference is, except that the EventTrigger class from the custom library work with Silverlight too.
In my example the trigger is subscribed to the event MouseLeftButtonDown and calls the special action class every time when the event is raised.
This action class is a custom class and it is defined in code:
/// <summary>
/// Behaviour helps to bind any RoutedEvent of UIElement to Command.
/// </summary>
[DefaultTrigger(typeof(UIElement), typeof(System.Windows.Interactivity.EventTrigger), "MouseLeftButtonDown")]
public class ExecuteCommandAction : TargetedTriggerAction<UIElement>
{
/// <summary>
/// Dependency property represents the Command of the behaviour.
/// </summary>
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.RegisterAttached("CommandParameter",
typeof(object), typeof(ExecuteCommandAction), new FrameworkPropertyMetadata(null));
/// <summary>
/// Dependency property represents the Command parameter of the behaviour.
/// </summary>
public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command",
typeof(ICommand), typeof(ExecuteCommandAction), new FrameworkPropertyMetadata(null));
/// <summary>
/// Gets or sets the Commmand.
/// </summary>
public ICommand Command
{
get
{
return (ICommand)this.GetValue(CommandProperty);
}
set
{
this.SetValue(CommandProperty, value);
}
}
/// <summary>
/// Gets or sets the CommandParameter.
/// </summary>
public object CommandParameter
{
get
{
return this.GetValue(CommandParameterProperty);
}
set
{
this.SetValue(CommandParameterProperty, value);
}
}
/// <summary>
/// Invoke method is called when the given routed event is fired.
/// </summary>
/// <param name="parameter">
/// Parameter is the sender of the event.
/// </param>
protected override void Invoke(object parameter)
{
if (this.Command != null)
{
if (this.Command.CanExecute(this.CommandParameter))
{
this.Command.Execute(this.CommandParameter);
}
}
}
}
That is all. Now the command doesn't prevent the tabcontrol from selection of items.
Code-behind to test this xaml:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var items = new ObservableCollection<TabItemViewModel>
{
new TabItemViewModel("Item 1"), new TabItemViewModel("Item 2"), new TabItemViewModel("Item 3")
};
this.DataContext = new MainViewModel(){TabItems = items};
}
}
public class MainViewModel
{
public ObservableCollection<TabItemViewModel> TabItems { get; set; }
}
public class TabItemViewModel
{
public TabItemViewModel(string title)
{
this.Title = title;
this.HeaderClickCommand = new RelayCommand(() => MessageBox.Show("Clicked "+this.Title));
}
public string Title { get; set; }
public RelayCommand HeaderClickCommand { get; set; }
}
To call the command only when an item is selected, change this code:
<local:ExecuteCommandAction Command="{Binding HeaderClickCommand}"
CommandParameter="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType=TabItem}}"/>
And this (the second parameter is the CanExecute delegate, it checks IsSelected == true):
this.HeaderClickCommand = new RelayCommand<bool>(b => {/*???*/}, b => b == true);

Resources