WPF UIElement Selection Change Events using Behaviors
https://www.imustread.com/2020/12/wpf-uielement-selection-change-events.html
WPF fulfills all the necessary requirements that are lacked while using Winforms. Splinter is a simplified WPF MVVM framework that provides exquisite features required for app development. It also supports excellent data binding for the controls.
Here, in this blog, we would see about the selection change event using behaviors in WPF. Selection Change Event is an event that occurs when there is a selection change. A selection can be changed using the user interface or using binding or using other values also. This type of event is SelectionChangedEventHandler, it represents the method that handles the route event of SelectionChanged.
Method: public delegate void SelectionChangedEventHandler (object obj, SelectionChangedEventArgs e);
Here, obj is an object where the event handler is attached and e is event data.
Let’s perform a simple example using SelectionChanged.
Here, we are going to create a simple window in which we will create the list box and one text block, when the item of the list box will select it will display in the text block using the SelectionChanged event.
XAML
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Name="tb" Width="140" Height="30" Grid.Row="0"></TextBox>
<ListBox Name="lb" SelectionChanged="PrintTxt" SelectionMode="Single" Grid.Row="1" Width="100" Height="100">
<ListBoxItem>Surat</ListBoxItem>
<ListBoxItem>Rajkot</ListBoxItem>
<ListBoxItem>Vapi</ListBoxItem>
<ListBoxItem>Valsad</ListBoxItem>
<ListBoxItem>Mahesana</ListBoxItem>
</ListBox>
</Grid>
Code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
void PrintTxt(object sender, SelectionChangedEventArgs args)
{
ListBoxItem lbi = ((sender as ListBox).SelectedItem as ListBoxItem);
tb.Text = lbi.Content.ToString() +" "+" city is Selected";
}
}
In the above window we have created a list box and when the item will select, the text block display message using the SelectionChanged event.
Binding Combo box Selection Change Event using behavior and routed event.
In this example, we will bind the combo box using selection changed event using MVVM ICommand interface, and attached behavior to the combo box.
We are going to create a data grid in this we will display text block and combo box, when the combo box item will select it will display a message inside the text block that will show the name and value of the combo box item which is changed old to a new value.
XAML
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
</Grid.RowDefinitions>
<DataGrid x:Name="McDataGrid" Margin="0" AutoGenerateColumns="False" ItemsSource="{Binding MainItems}">
<DataGrid.Columns>
<DataGridTextColumn Width="*" Binding="{Binding Name}" Header="Name" IsReadOnly="True"/>
<DataGridTemplateColumn MinWidth="200" Width="Auto" Header="Departments">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Items}"
SelectedItem="{Binding Department}"
local:SelectionChangedBehavior.SelectionChangedEvent="{Binding SelectionChangeCommand}">
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<TextBlock Grid.Row="1" Text="{Binding Message}"/>
</Grid>
Code behind file:
Here, we are binding View Model using data context.
Public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
In the above window, we have created a data grid and display combo box and text, and text block to bind all of these.
ViewModel:
public class MainViewModel : INotifyPropertyChanged
{
private string message;
public string Message
{
get
{
return message;
}
set
{
message = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Message)));
}
}
public ObservableCollection<string> Departments = new ObservableCollection<string> { "Admin", "Development", "Tranining", "Others" };
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<EmployeeVM> MainItems { get; set; }
public MainViewModel()
{
MainItems = new ObservableCollection<EmployeeVM> { new EmployeeVM("Senior software engineer", this), new EmployeeVM("Junior software engineer", this) , new EmployeeVM("Trainee engineer", this) };
}
}
public class EmployeeVM
{
public EmployeeVM(string name, MainViewModel parent)
{
SelectionChangeCommand = new MyCustomCommand<SelectionChangedEventArgs>(OnSelectionChange);
Name = name;
Parent = parent;
Department = "Development";
}
private void OnSelectionChange(SelectionChangedEventArgs obj)
{
Parent.Message = $"Combo box selection Changed from {obj.RemovedItems[0]} to {obj.AddedItems[0]}" + " " + "of" +" "+ Name;
}
public ObservableCollection<string> Items => Parent.Departments;
public ICommand SelectionChangeCommand { get; set; }
public string Name { get; set; }
public MainViewModel Parent { get; }
public string Department { get; set; }
}
public class MyCustomCommand<T> : ICommand
{
private Action<T> execute;
private Func<T, bool> canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public MyCustomCommand(Action<T> execute, Func<T, bool> canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute((T)parameter);
}
public void Execute(object parameter)
{
this.execute((T)parameter);
}
}
Class SelectionChangebehavior
public static class SelectionChangedBehavior
{
private static readonly DependencyProperty SelectionChangedEvent =
DependencyProperty.RegisterAttached(
"SelectionChangedEvent",
typeof(ICommand),
typeof(SelectionChangedBehavior),
new PropertyMetadata(null, new ExecuteCommandOnRoutedEvent(Selector.SelectionChangedEvent).PropertyChangedHandler));
public static void SetSelectionChangedEvent(DependencyObject dependencyObject, ICommand value)
{
dependencyObject.SetValue(SelectionChangedEvent, value);
}
public static ICommand GetSelectionChangedEvent(DependencyObject dependencyObject)
{
return (ICommand)dependencyObject.GetValue(SelectionChangedEvent);
}
}
public class ExecuteCommandOnRoutedEvent
{
private readonly RoutedEvent routed;
private DependencyProperty property;
public ExecuteCommandOnRoutedEvent(RoutedEvent @event)
{
routed = @event;
}
private void ManageEventHandlers(DependencyObject sender, object oldValue, object newValue)
{
var element = sender as UIElement;
if (element == null)
{
return;
}
if (oldValue != null)
{
element.RemoveHandler(routed, new RoutedEventHandler(CommandEventHandler));
}
if (newValue != null)
{
element.AddHandler(routed, new RoutedEventHandler(CommandEventHandler));
}
}
private void CommandEventHandler(object sender, RoutedEventArgs e)
{
var dp = sender as DependencyObject;
if (dp == null)
{
return;
}
var command = dp.GetValue(property) as ICommand;
if (command == null)
{
return;
}
if (command.CanExecute(e))
{
command.Execute(e);
}
}
public void PropertyChangedHandler(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
property = e.Property;
var oldValue = e.OldValue;
var newValue = e.NewValue;
ManageEventHandlers(sender, oldValue, newValue);
}
}
In the above class, we have written behavior with Dependency property SelectionChangeEvent with PropertyChangecallBack property.
Class EditableComboBoxBehavior
public static class EditableComboBoxBehavior
{
public static readonly DependencyProperty AcceptsEnterKeyProperty =
DependencyProperty.RegisterAttached("AcceptsEnterKey", typeof(bool), typeof(EditableComboBoxBehavior), new PropertyMetadata(default(bool), OnAcceptsEnterKey));
public static void SetAcceptsEnterKey(DependencyObject element, bool value)
{
element.SetValue(AcceptsEnterKeyProperty, value);
}
public static bool GetAcceptsEnterKey(DependencyObject element)
{
return (bool)element.GetValue(AcceptsEnterKeyProperty);
}
private static void OnAcceptsEnterKey(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
{
var element = (UIElement)dependencyObject;
if ((bool)eventArgs.NewValue)
{
element.PreviewKeyDown += KeyDownPreview;
element.KeyUp += KeyDown;
}
else
{
element.PreviewKeyDown -= KeyDownPreview;
element.KeyUp -= KeyDown;
}
}
private static void KeyDownPreview(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter || e.Key == Key.Return)
{
}
}
private static void KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter || e.Key == Key.Return)
{
}
else
{
var comboBox = (ComboBox)sender;
var text = comboBox.Text;
comboBox.IsDropDownOpen = false;
}
}
}
Class ExecuteCommandOnRoutedEventBehavior
internal class ExecuteCommandOnRoutedEventBehavior
{
private RoutedEvent routedEvent;
public ExecuteCommandOnRoutedEventBehavior(RoutedEvent routedEvent)
{
this.routedEvent = routedEvent;
}
}
In the above window, we have displayed a message when a combo box item will select.
Conclusion
In this blog, we have discussed the Selection change event in WPF and also its usage of it. We have performed two practicals, in the first example we have used the selection changed property inside Listbox and display the selected List item to the text block using the selection changed event, and in the second example, we have created a window that contains a data grid with text and combo box. When the item of the combo box will select it will display inside the text block.
Technocrat and entrepreneur with years of experience building large-scale enterprise web, cloud, and mobile applications using the latest technologies like ASP.NET, CORE, .NET MVC, Angular and Blockchain. Keen interest in addressing business problems using the latest technologies and have been associated with WPF Application development companies