An attached property is similar to a dependency property, but it is not tightly bound to a particular type of control. It can be attached to any control.
It's not uncommon for these kinds of requirements to be added to mature products. You could create a subclassed control and add a dependency property to handle this requirement, but every datagrid would have to be replaced with the subclassed version which can be very intrusive in a mature product. The attached property approach simply adds new functionality to an existing control.
Start a new WPF C# project and target framework 4.0 or later. Call it Behavior. We will create a list box and a button. When the user clicks the button we will call the SelectAll method of the list box without having a reference to the list box.
Add a new class to hold the behavior and call it SelectAllBehavior. An attached property is declared similarly to a dependency property. I've bolded the important part. It specifies code to be executed when the property value changes. This code receives a reference to the control that the property is bound to. Once we see the property is being set true, we can call the SelectAll method, and set the property back to false.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Data;
namespace Behavior
{
class SelectAllBehavior
{
public static readonly DependencyProperty
SelectAllProperty = DependencyProperty.RegisterAttached("SelectAll", typeof(bool),
typeof(SelectAllBehavior), new PropertyMetadata(false, (o, e) =>
{
ListBox lb = o as ListBox;
if (lb == null) return;
if ((bool)e.NewValue)
{
lb.SelectAll();
// Not sure if there's an easier way to do this, but SetValue
doesn't update the bound property
BindingExpression be =
BindingOperations.GetBindingExpression(lb, SelectAllProperty);
string PropertyName =
be.ParentBinding.Path.Path;
be.DataItem.GetType().GetProperty(PropertyName).SetValue(be.DataItem, false);
}
}
));
public static bool GetSelectAll(DependencyObject o)
{
return (bool)o.GetValue(SelectAllProperty);
}
public static void SetSelectAll(DependencyObject o, bool value)
{
o.SetValue(SelectAllProperty,
value);
}
}
}
<Window x:Class="Behavior.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:Behavior"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<RoutedCommand x:Key="SelectCommand"/>
</Window.Resources>
<Window.CommandBindings>
<CommandBinding Command="{StaticResource SelectCommand}" Executed="CommandBinding_Executed"/>
</Window.CommandBindings>
<Grid>
<StackPanel Orientation="Horizontal" Height="100">
<ListBox local:SelectAllBehavior.SelectAll="{Binding SelectAll, Mode=TwoWay}" SelectionMode="Extended">
<ListBox.Items>
<ListBoxItem Content="ALPHA"/>
<ListBoxItem Content="BETA"/>
<ListBoxItem Content="GAMMA"/>
</ListBox.Items>
</ListBox>
<Button Height="22" Content="Select All" Command="{StaticResource SelectCommand}"/>
</StackPanel>
</Grid>
</Window>
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
namespace Behavior
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
}
private bool
_SelectAll;
public bool
SelectAll
{
get { return
_SelectAll; }
set
{
_SelectAll = value;
PropChanged("SelectAll");
}
}
private void
CommandBinding_Executed(object sender,
ExecutedRoutedEventArgs e)
{
SelectAll = true;
}
public event
PropertyChangedEventHandler PropertyChanged;
public void
PropChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
You could attach this to different list boxes and even controls that are not list boxes, although the code would need to be enhanced to deal with non-listbox controls.
Take a look at the list box before and after the button is clicked.
Before click |
After click |
No comments:
Post a Comment