Browse Source

1. Add FilterBox for CheckComboBox and CheckListBox controls. 2. New AllowFilter dependency property for both controls.

pull/1221/head
Roman Korneev 9 years ago
parent
commit
260b0183fb
  1. 20
      ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit.LiveExplorer/Samples/CheckLists/Views/CheckListsView.xaml
  2. 29
      ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit.LiveExplorer/Samples/CheckLists/Views/CheckListsView.xaml.cs
  3. 63
      ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/CheckComboBox/Implementation/CheckComboBox.cs
  4. 35
      ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/CheckComboBox/Themes/Aero2.NormalColor.xaml
  5. 17
      ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/CheckComboBox/Themes/Generic.xaml
  6. 60
      ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/CheckListBox/Implementation/CheckListBox.cs
  7. 17
      ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/CheckListBox/Themes/Aero2.NormalColor.xaml
  8. 13
      ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/CheckListBox/Themes/Generic.xaml
  9. BIN
      ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/FilterBox/Images/icon-search.png
  10. 299
      ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/FilterBox/Implementation/FilterBox.cs
  11. 120
      ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/FilterBox/Themes/Aero2.NormalColor.xaml
  12. 120
      ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/FilterBox/Themes/Genreric.xaml
  13. 12
      ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/Xceed.Wpf.Toolkit.csproj

20
ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit.LiveExplorer/Samples/CheckLists/Views/CheckListsView.xaml

@ -49,6 +49,7 @@
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
@ -99,6 +100,16 @@
IsEnabled="False"
Text="IsSelected" />
<TextBlock Grid.Row="4" Grid.Column="0"
Text="AllowFilter:"
Margin="2,5,5,5"/>
<CheckBox x:Name="_isAllowFilter"
Grid.Row="4" Grid.Column="1"
Margin="5"
HorizontalAlignment="Left"
ClickMode="Press"
IsChecked="False" />
<TextBlock Grid.Row="0" Grid.Column="2"
Text="DisplayMemberPath:"
Margin="5"/>
@ -151,8 +162,7 @@
</GroupBox>
<GroupBox Header="Item Models" Grid.Row="1" Margin="5">
<ListBox DisplayMemberPath="ModelDisplay" FontFamily="Global Monospace"
ItemsSource="{Binding}"/>
<ListBox x:Name="_itemModels" DisplayMemberPath="ModelDisplay" FontFamily="Global Monospace"/>
</GroupBox>
<Grid Grid.Row="2">
@ -171,11 +181,11 @@
Grid.Row="1"
Margin="5"
VerticalAlignment="Stretch"
ItemsSource="{Binding}"
Delimiter="{Binding ElementName=_delimiter, Path=Text}"
ValueMemberPath="{Binding ElementName=_valueMemberPath, Path=SelectedItem}"
SelectedMemberPath="{Binding ElementName=_selectedMemberPath, Path=Text}"
DisplayMemberPath="{Binding ElementName=_displayMemberPath, Path=SelectedItem}" />
DisplayMemberPath="{Binding ElementName=_displayMemberPath, Path=SelectedItem}"
AllowFilter="{Binding ElementName=_isAllowFilter, Path=IsChecked}" />
<TextBlock Text="CheckComboBox Usage:" Grid.Column="1" Margin="5" Style="{StaticResource Header}"/>
<xctk:CheckComboBox Grid.Column="1"
@ -183,11 +193,11 @@
Grid.Row="1"
Margin="5"
VerticalAlignment="Top"
ItemsSource="{Binding}"
Delimiter="{Binding ElementName=_delimiter, Path=Text}"
ValueMemberPath="{Binding ElementName=_valueMemberPath, Path=SelectedItem}"
SelectedMemberPath="{Binding ElementName=_selectedMemberPath, Path=Text}"
DisplayMemberPath="{Binding ElementName=_displayMemberPath, Path=SelectedItem}"
AllowFilter="{Binding ElementName=_isAllowFilter, Path=IsChecked}"
IsEditable="False"
IsDropDownOpen="false"
MaxDropDownHeight="100"/>

29
ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit.LiveExplorer/Samples/CheckLists/Views/CheckListsView.xaml.cs

@ -15,7 +15,6 @@
*************************************************************************************/
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace Xceed.Wpf.Toolkit.LiveExplorer.Samples.CheckLists.Views
@ -28,20 +27,26 @@ namespace Xceed.Wpf.Toolkit.LiveExplorer.Samples.CheckLists.Views
public CheckListsView()
{
InitializeComponent();
this.DataContext = new List<Person>()
_itemModels.ItemsSource = GetData();
_checkListBox.ItemsSource = GetData();
_checkComboBox.ItemsSource = GetData();
}
private static List<Person> GetData()
{
return new List<Person>
{
new Person(){ID=101, FirstName="John", LastName="Smith"},
new Person(){ID=102, FirstName="Janel", LastName="Leverling"},
new Person(){ID=103, FirstName="Laura", LastName="Callahan"},
new Person(){ID=104, FirstName="Robert", LastName="King"},
new Person(){ID=105, FirstName="Margaret", LastName="Peacock"},
new Person(){ID=106, FirstName="Andrew", LastName="Fuller"},
new Person(){ID=107, FirstName="Anne", LastName="Dodsworth"},
new Person(){ID=108, FirstName="Nancy", LastName="Davolio"},
new Person(){ID=109, FirstName="Naomi", LastName="Suyama"},
new Person {ID=101, FirstName="John", LastName="Smith"},
new Person {ID=102, FirstName="Janel", LastName="Leverling"},
new Person {ID=103, FirstName="Laura", LastName="Callahan"},
new Person {ID=104, FirstName="Robert", LastName="King"},
new Person {ID=105, FirstName="Margaret", LastName="Peacock"},
new Person {ID=106, FirstName="Andrew", LastName="Fuller"},
new Person {ID=107, FirstName="Anne", LastName="Dodsworth"},
new Person {ID=108, FirstName="Nancy", LastName="Davolio"},
new Person {ID=109, FirstName="Naomi", LastName="Suyama"},
};
}
}
public class Person : INotifyPropertyChanged

63
ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/CheckComboBox/Implementation/CheckComboBox.cs

@ -5,7 +5,7 @@
Copyright (C) 2007-2013 Xceed Software Inc.
This program is provided to you under the terms of the Microsoft Public
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
For more features, controls, and fast professional support,
pick up the Plus Edition at http://xceed.com/wpf_toolkit
@ -18,26 +18,28 @@ using System;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using Xceed.Wpf.Toolkit.Primitives;
using Xceed.Wpf.Toolkit.Core.Utilities;
using System.Windows.Controls;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Controls.Primitives;
using Xceed.Wpf.Toolkit.Core.Utilities;
namespace Xceed.Wpf.Toolkit
{
[TemplatePart( Name = PART_Popup, Type = typeof( Popup ) )]
[TemplatePart(Name = PART_FilterBox, Type = typeof(FilterBox))]
public class CheckComboBox : Xceed.Wpf.Toolkit.Primitives.Selector
{
private const string PART_Popup = "PART_Popup";
private const string PART_FilterBox = "PART_FilterBox";
#region Members
private ValueChangeHelper _displayMemberPathValuesChangeHelper;
private readonly ValueChangeHelper _displayMemberPathValuesChangeHelper;
private bool _ignoreTextValueChanged;
private Popup _popup;
private List<object> _initialValue = new List<object>();
private FilterBox _filterBox;
private readonly List<object> _initialValue = new List<object>();
private bool _allowFilter;
#endregion
@ -179,6 +181,48 @@ namespace Xceed.Wpf.Toolkit
#endregion
#region AllowFilter
public static readonly DependencyProperty AllowFilterProperty = DependencyProperty.Register(
"AllowFilter",
typeof(bool),
typeof(CheckComboBox),
new UIPropertyMetadata(true, AllowFilterChanged));
private static void AllowFilterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var selector = d as CheckComboBox;
if (selector != null)
selector.AllowFilterChanged((bool) e.NewValue);
}
protected void AllowFilterChanged(bool value)
{
_allowFilter = value;
if (_filterBox != null)
{
SetFilter(value);
}
}
public bool AllowFilter
{
get
{
return (bool)GetValue(AllowFilterProperty);
}
set
{
SetValue(AllowFilterProperty, value);
}
}
private void SetFilter(bool value)
{
_filterBox.Clear(false);
_filterBox.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
}
#endregion //AllowFilter
#endregion //Properties
#region Base Class Overrides
@ -212,6 +256,9 @@ namespace Xceed.Wpf.Toolkit
if( _popup != null )
_popup.Opened += Popup_Opened;
_filterBox = GetTemplateChild( PART_FilterBox ) as FilterBox;
SetFilter(_allowFilter);
}
#endregion //Base Class Overrides
@ -273,7 +320,7 @@ namespace Xceed.Wpf.Toolkit
protected virtual void UpdateText()
{
#if VS2008
string newValue = String.Join( Delimiter, SelectedItems.Cast<object>().Select( x => GetItemDisplayValue( x ).ToString() ).ToArray() );
string newValue = String.Join( Delimiter, SelectedItems.Cast<object>().Select( x => GetItemDisplayValue( x ).ToString() ).ToArray() );
#else
string newValue = String.Join( Delimiter, SelectedItems.Cast<object>().Select( x => GetItemDisplayValue( x ) ) );
#endif

35
ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/CheckComboBox/Themes/Aero2.NormalColor.xaml

@ -21,6 +21,10 @@
xmlns:themes="clr-namespace:Xceed.Wpf.Toolkit.Themes"
xmlns:chrome="clr-namespace:Xceed.Wpf.Toolkit.Chromes">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../../FilterBox/Themes/Aero2.NormalColor.xaml" />
</ResourceDictionary.MergedDictionaries>
<conv:InverseBoolConverter x:Key="InverseBoolConverter" />
<Geometry x:Key="DownArrowGeometry">M 0,1 C0,1 0,0 0,0 0,0 3,0 3,0 3,0 3,1 3,1 3,1 4,1 4,1 4,1 4,0 4,0 4,0 7,0 7,0 7,0 7,1 7,1 7,1 6,1 6,1 6,1 6,2 6,2 6,2 5,2 5,2 5,2 5,3 5,3 5,3 4,3 4,3 4,3 4,4 4,4 4,4 3,4 3,4 3,4 3,3 3,3 3,3 2,3 2,3 2,3 2,2 2,2 2,2 1,2 1,2 1,2 1,1 1,1 1,1 0,1 0,1 z</Geometry>
@ -50,8 +54,9 @@
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}"
Width="0" />
<ColumnDefinition
MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}"
Width="0" />
</Grid.ColumnDefinitions>
<TextBox x:Name="TextBox"
@ -93,8 +98,9 @@
TargetName="Arrow"
Value="#AFAFAF" />
</Trigger>
<DataTrigger Binding="{Binding IsEditable, RelativeSource={RelativeSource AncestorType={x:Type local:CheckComboBox}}}"
Value="True">
<DataTrigger
Binding="{Binding IsEditable, RelativeSource={RelativeSource AncestorType={x:Type local:CheckComboBox}}}"
Value="True">
<Setter Property="IsReadOnly"
Value="False"
TargetName="TextBox" />
@ -165,18 +171,25 @@
Height="{Binding ActualHeight, ElementName=DropDownBorder}"
Width="{Binding ActualWidth, ElementName=DropDownBorder}" />
</Canvas>
<ItemsPresenter x:Name="PART_ItemsPresenter"
KeyboardNavigation.DirectionalNavigation="Contained"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<DockPanel>
<local:FilterBox x:Name="PART_FilterBox"
DockPanel.Dock="Top"
Header="Type here to filter"
TargetControl="{Binding Path=., RelativeSource={RelativeSource TemplatedParent}}"
FilterTextBindingPath="{TemplateBinding DisplayMemberPath}" />
<ItemsPresenter x:Name="PART_ItemsPresenter"
KeyboardNavigation.DirectionalNavigation="Contained"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</DockPanel>
</Grid>
</ScrollViewer>
</Border>
</Grid>
</Popup>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" />
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" />
<ToggleButton x:Name="PART_DropDownButton"
Content="{Binding Text, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
BorderBrush="{TemplateBinding BorderBrush}"
@ -206,4 +219,4 @@
</Style.Triggers>
</Style>
</ResourceDictionary>
</ResourceDictionary>

17
ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/CheckComboBox/Themes/Generic.xaml

@ -20,6 +20,10 @@
xmlns:conv="clr-namespace:Xceed.Wpf.Toolkit.Core.Converters"
xmlns:chrome="clr-namespace:Xceed.Wpf.Toolkit.Chromes">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../../FilterBox/Themes/Genreric.xaml" />
</ResourceDictionary.MergedDictionaries>
<conv:InverseBoolConverter x:Key="InverseBoolConverter" />
<SolidColorBrush x:Key="ButtonNormalBorder"
@ -167,9 +171,16 @@
Height="{Binding ActualHeight, ElementName=DropDownBorder}"
Width="{Binding ActualWidth, ElementName=DropDownBorder}" />
</Canvas>
<ItemsPresenter x:Name="PART_ItemsPresenter"
KeyboardNavigation.DirectionalNavigation="Contained"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<DockPanel>
<local:FilterBox x:Name="PART_FilterBox"
DockPanel.Dock="Top"
Header="Type here to filter"
TargetControl="{Binding Path=., RelativeSource={RelativeSource TemplatedParent}}"
FilterTextBindingPath="{TemplateBinding DisplayMemberPath}" />
<ItemsPresenter x:Name="PART_ItemsPresenter"
KeyboardNavigation.DirectionalNavigation="Contained"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</DockPanel>
</Grid>
</ScrollViewer>
</Border>

60
ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/CheckListBox/Implementation/CheckListBox.cs

@ -19,8 +19,60 @@ using Xceed.Wpf.Toolkit.Primitives;
namespace Xceed.Wpf.Toolkit
{
[TemplatePart(Name = PART_FilterBox, Type = typeof(FilterBox))]
public class CheckListBox : Selector
{
private const string PART_FilterBox = "PART_FilterBox";
#region Members
private FilterBox _filterBox;
private bool _allowFilter;
#endregion
#region AllowFilter
public static readonly DependencyProperty AllowFilterProperty = DependencyProperty.Register(
"AllowFilter",
typeof(bool),
typeof(CheckListBox),
new UIPropertyMetadata(true, AllowFilterChanged));
private static void AllowFilterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var selector = d as CheckListBox;
if (selector != null)
selector.AllowFilterChanged((bool)e.NewValue);
}
protected void AllowFilterChanged(bool value)
{
_allowFilter = value;
if (_filterBox != null)
{
SetFilter(value);
}
}
public bool AllowFilter
{
get
{
return (bool)GetValue(AllowFilterProperty);
}
set
{
SetValue(AllowFilterProperty, value);
}
}
private void SetFilter(bool value)
{
_filterBox.Clear(false);
_filterBox.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
}
#endregion //AllowFilter
#region Constructors
static CheckListBox()
@ -34,5 +86,13 @@ namespace Xceed.Wpf.Toolkit
}
#endregion //Constructors
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_filterBox = GetTemplateChild(PART_FilterBox) as FilterBox;
SetFilter(_allowFilter);
}
}
}

17
ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/CheckListBox/Themes/Aero2.NormalColor.xaml

@ -19,8 +19,12 @@
xmlns:themes="clr-namespace:Xceed.Wpf.Toolkit.Themes"
xmlns:local="clr-namespace:Xceed.Wpf.Toolkit">
<Style TargetType="{x:Type local:CheckListBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../../FilterBox/Themes/Aero2.NormalColor.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type local:CheckListBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static themes:ResourceKeys.ControlNormalBorderKey}}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="KeyboardNavigation.TabNavigation" Value="Once" />
@ -29,7 +33,14 @@
<ControlTemplate TargetType="{x:Type local:CheckListBox}">
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer Padding="{TemplateBinding Padding}" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<DockPanel>
<local:FilterBox x:Name="PART_FilterBox"
DockPanel.Dock="Top"
Header="Type here to filter"
TargetControl="{Binding Path=., RelativeSource={RelativeSource TemplatedParent}}"
FilterTextBindingPath="{TemplateBinding DisplayMemberPath}" />
<ItemsPresenter DockPanel.Dock="Top" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</DockPanel>
</ScrollViewer>
</Border>
</ControlTemplate>

13
ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/CheckListBox/Themes/Generic.xaml

@ -18,6 +18,10 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Xceed.Wpf.Toolkit">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../../FilterBox/Themes/Genreric.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type local:CheckListBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
<Setter Property="BorderBrush" Value="#FF707070" />
@ -30,7 +34,14 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer Padding="{TemplateBinding Padding}" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<DockPanel>
<local:FilterBox x:Name="PART_FilterBox"
DockPanel.Dock="Top"
Header="Type here to filter"
TargetControl="{Binding Path=., RelativeSource={RelativeSource TemplatedParent}}"
FilterTextBindingPath="{TemplateBinding DisplayMemberPath}" />
<ItemsPresenter DockPanel.Dock="Top" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</DockPanel>
</ScrollViewer>
</Border>
</ControlTemplate>

BIN
ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/FilterBox/Images/icon-search.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

299
ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/FilterBox/Implementation/FilterBox.cs

@ -0,0 +1,299 @@
using System;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
namespace Xceed.Wpf.Toolkit
{
public delegate void FilterRoutedEventHandler(object sender, FilterEventArgs e);
[TemplatePart(Name = PART_Header, Type = typeof(TextBlock))]
[TemplatePart(Name = PART_FilterBox, Type = typeof(TextBox))]
[TemplatePart(Name = PART_ClearButton, Type = typeof(Button))]
public sealed class FilterBox : Control
{
#region [ Declarations and Fields ]
private const string PART_Header = "PART_Header";
private const string PART_FilterBox = "PART_FilterBox";
private const string PART_ClearButton = "PART_ClearButton";
public static readonly RoutedEvent FilterEvent;
public static readonly RoutedEvent ClearFilterEvent;
private Button _clearButton;
private TextBox _filterBox;
private TextBlock _headerText;
#endregion
#region [ Constructors ]
static FilterBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FilterBox), new FrameworkPropertyMetadata(typeof(FilterBox)));
FilterEvent = EventManager.RegisterRoutedEvent("Filter", RoutingStrategy.Bubble, typeof(FilterRoutedEventHandler), typeof(FilterBox));
ClearFilterEvent = EventManager.RegisterRoutedEvent("ClearFilter", RoutingStrategy.Bubble, typeof(RoutedEventArgs), typeof(FilterBox));
}
#endregion
#region [ FilterText property ]
public static readonly DependencyProperty FilterTextProperty =
DependencyProperty.Register("FilterText", typeof(string), typeof(FilterBox), new PropertyMetadata(string.Empty));
public string FilterText
{
get => (string)GetValue(FilterTextProperty);
set => SetValue(FilterTextProperty, value);
}
#endregion
#region Header property
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(string), typeof(FilterBox), new UIPropertyMetadata(string.Empty));
public string Header
{
get => (string)GetValue(HeaderProperty);
set => SetValue(HeaderProperty, value);
}
#endregion
#region TargetControl property
public static readonly DependencyProperty TargetControlProperty =
DependencyProperty.Register("TargetControl", typeof(ItemsControl), typeof(FilterBox), new UIPropertyMetadata(null));
public ItemsControl TargetControl
{
get => (ItemsControl)GetValue(TargetControlProperty);
set => SetValue(TargetControlProperty, value);
}
#endregion
#region FilterTextBindingPath property
public static readonly DependencyProperty FilterTextBindingPathProperty =
DependencyProperty.Register("FilterTextBindingPath", typeof(string), typeof(FilterBox), new PropertyMetadata(string.Empty));
public string FilterTextBindingPath
{
get => (string)GetValue(FilterTextBindingPathProperty);
set => SetValue(FilterTextBindingPathProperty, value);
}
#endregion
#region FilterOnEnter property
public static readonly DependencyProperty FilterOnEnterProperty =
DependencyProperty.Register("FilterOnEnter", typeof(bool), typeof(FilterBox), new UIPropertyMetadata(false));
public bool FilterOnEnter
{
get => (bool)GetValue(FilterOnEnterProperty);
set => SetValue(FilterOnEnterProperty, value);
}
public bool HasFocus => _filterBox.IsFocused;
#endregion
#region Filter event
public event FilterRoutedEventHandler Filter
{
add => base.AddHandler(FilterEvent, value);
remove => base.RemoveHandler(FilterEvent, value);
}
#endregion
#region ClearFilter event
public event RoutedEventHandler ClearFilter
{
add => base.AddHandler(ClearFilterEvent, value);
remove => base.RemoveHandler(ClearFilterEvent, value);
}
#endregion
#region Overridden Functions/Methods
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
AttachToVisualTree();
}
#endregion
#region [ Private Functions/Methods ]
private void ApplyFilterOnTarget()
{
if (TargetControl?.ItemsSource == null)
return;
var collectionView = CollectionViewSource.GetDefaultView(TargetControl.ItemsSource);
if (collectionView == null)
throw new InvalidOperationException("The TargetConrol should use ICollectionView as ItemSource.");
collectionView.Filter =
m => Regex.IsMatch(
GetDataValue<string>(m, FilterTextBindingPath),
Regex.Escape(FilterText),
RegexOptions.IgnoreCase
);
}
private void ClearFilterOnTarget()
{
if (TargetControl?.ItemsSource == null)
return;
var collectionView = CollectionViewSource.GetDefaultView(TargetControl.ItemsSource);
if (collectionView == null)
throw new InvalidOperationException("The TargetConrol should use ICollectionView as ItemSource.");
collectionView.Filter = null;
}
private void RaiseFilterEvent()
{
var args = new FilterEventArgs(FilterEvent, this, this.FilterText);
RaiseEvent(args);
if (!args.IsFilterApplied)
ApplyFilterOnTarget();
}
private static T GetDataValue<T>(object data, string propertyName)
{
if (!string.IsNullOrEmpty(propertyName))
{
var descriptors = TypeDescriptor.GetProperties(data.GetType());
var descriptor = descriptors[propertyName];
if (descriptor != null)
{
var value = (T)descriptor.GetValue(data);
return value;
}
}
return (T)Convert.ChangeType(data.ToString(), typeof(T));
}
private void AttachToVisualTree()
{
_headerText = GetTemplateChild(PART_Header) as TextBlock;
_filterBox = GetTemplateChild(PART_FilterBox) as TextBox;
if (_filterBox != null)
{
_filterBox.LostKeyboardFocus += OnLostKeyboardFocus;
_filterBox.GotKeyboardFocus += OnGotKeyboardFocus;
_filterBox.TextChanged += OnFilterBoxTextChanged;
}
_clearButton = GetTemplateChild(PART_ClearButton) as Button;
if (_clearButton != null)
{
_clearButton.Click += OnClearButtonClick;
}
GotKeyboardFocus += FilterGotKeyboardFocus;
KeyDown += OnKeyDown;
}
private void FilterGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
Keyboard.Focus(_filterBox);
_filterBox.CaretBrush = Foreground;
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape && !string.IsNullOrEmpty(FilterText))
{
Clear();
}
else if (e.Key == Key.Enter && FilterOnEnter)
{
RaiseFilterEvent();
}
}
private void OnClearButtonClick(object sender, RoutedEventArgs e)
{
Clear();
}
public void Clear(bool setFocus = true)
{
if (_filterBox != null)
{
_filterBox.Text = string.Empty;
if (setFocus)
Keyboard.Focus(_filterBox);
var args = new RoutedEventArgs(ClearFilterEvent, this);
RaiseEvent(args);
if (!args.Handled)
ClearFilterOnTarget();
}
}
private void OnFilterBoxTextChanged(object sender, TextChangedEventArgs e)
{
if (!FilterOnEnter)
{
RaiseFilterEvent();
}
if (string.IsNullOrEmpty(_filterBox.Text))
{
_clearButton.Visibility = Visibility.Collapsed;
_headerText.Visibility = !_filterBox.IsFocused ? Visibility.Visible : Visibility.Collapsed;
}
else
{
_clearButton.Visibility = Visibility.Visible;
_headerText.Visibility = Visibility.Collapsed;
}
}
private void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
_headerText.Visibility = Visibility.Collapsed;
}
private void OnLostKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
{
if (string.IsNullOrEmpty(_filterBox.Text))
_headerText.Visibility = Visibility.Visible;
_filterBox.CaretBrush = new SolidColorBrush(Colors.Transparent);
}
#endregion
}
public class FilterEventArgs : RoutedEventArgs
{
public string FilterText
{
get;
}
public bool IsFilterApplied
{
get;
set;
}
public FilterEventArgs()
{
FilterText = null;
IsFilterApplied = false;
}
public FilterEventArgs(RoutedEvent routedEvent, object source) :
this(routedEvent, source, string.Empty)
{
}
public FilterEventArgs(RoutedEvent routedEvent, object source, string filterText)
: base(routedEvent, source)
{
FilterText = filterText;
}
}
}

120
ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/FilterBox/Themes/Aero2.NormalColor.xaml

@ -0,0 +1,120 @@
<ResourceDictionary
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:themes="clr-namespace:Xceed.Wpf.Toolkit.Themes"
xmlns:local="clr-namespace:Xceed.Wpf.Toolkit"
mc:Ignorable="d">
<!-- Style for the Clear Button -->
<Style x:Key="ClearButtonStyle" TargetType="{x:Type Button}">
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border
CornerRadius="2"
Background="{TemplateBinding Background}"
BorderThickness="1"
BorderBrush="{TemplateBinding BorderBrush}"
Width="16" Height="16"
SnapsToDevicePixels="True">
<Grid Width="8" Height="8" HorizontalAlignment="Center" VerticalAlignment="Center">
<Path x:Name="path1" Stroke="#ADADAD" Data="M0,0 L8,8" StrokeThickness="2" />
<Path x:Name="path2" Stroke="#ADADAD" Data="M8,0 L0,8" StrokeThickness="2" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static themes:ResourceKeys.ControlMouseOverBorderKey}}" />
<Setter Property="Background" Value="WhiteSmoke"/>
<Setter Property="Stroke" TargetName="path1" Value="DarkRed"/>
<Setter Property="Stroke" TargetName="path2" Value="DarkRed"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFADADAD" Offset="0"/>
<GradientStop Color="White" Offset="0.5"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="FilterTextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static themes:ResourceKeys.ControlNormalBorderKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="0,0,0,0"/>
</Style>
<Style TargetType="{x:Type local:FilterBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="FilterOnEnter" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:FilterBox}">
<Border Background="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}">
<Grid Margin="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Background="{TemplateBinding Background}" Grid.ColumnSpan="3" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
<Image Grid.Column="0" Source="../Images/icon-search.png"/>
<TextBox Style="{StaticResource FilterTextBoxStyle}"
x:Name="PART_FilterBox"
AutoWordSelection="True"
Grid.Column="1"
Margin="0,1,0,1"
VerticalAlignment="Center"
Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:FilterBox}}, Path=FilterText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock x:Name="PART_Header"
Text="{TemplateBinding Header}"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="2,0,0,0"
Grid.Column="1"
IsHitTestVisible="False"/>
<Button x:Name="PART_ClearButton"
Grid.Column="2"
Margin="0,0,4,0"
Style="{StaticResource ClearButtonStyle}"
Visibility="Collapsed"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

120
ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/FilterBox/Themes/Genreric.xaml

@ -0,0 +1,120 @@
<ResourceDictionary
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:themes="clr-namespace:Xceed.Wpf.Toolkit.Themes"
xmlns:local="clr-namespace:Xceed.Wpf.Toolkit"
mc:Ignorable="d">
<!-- Style for the Clear Button -->
<Style x:Key="ClearButtonStyle" TargetType="{x:Type Button}">
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border
CornerRadius="2"
Background="{TemplateBinding Background}"
BorderThickness="1"
BorderBrush="{TemplateBinding BorderBrush}"
Width="16" Height="16"
SnapsToDevicePixels="True">
<Grid Width="8" Height="8" HorizontalAlignment="Center" VerticalAlignment="Center">
<Path x:Name="path1" Stroke="#ADADAD" Data="M0,0 L8,8" StrokeThickness="2" />
<Path x:Name="path2" Stroke="#ADADAD" Data="M8,0 L0,8" StrokeThickness="2" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush"
Value="{DynamicResource {x:Static themes:ResourceKeys.ControlMouseOverBorderKey}}" />
<Setter Property="Background" Value="WhiteSmoke"/>
<Setter Property="Stroke" TargetName="path1" Value="DarkRed"/>
<Setter Property="Stroke" TargetName="path2" Value="DarkRed"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFADADAD" Offset="0"/>
<GradientStop Color="White" Offset="0.5"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="FilterTextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static themes:ResourceKeys.ControlNormalBorderKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="0,0,0,0"/>
</Style>
<Style TargetType="{x:Type local:FilterBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="FilterOnEnter" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:FilterBox}">
<Border Background="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}">
<Grid Margin="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Background="{TemplateBinding Background}" Grid.ColumnSpan="3" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
<Image Grid.Column="0" Source="../Images/icon-search.png"/>
<TextBox Style="{StaticResource FilterTextBoxStyle}"
x:Name="PART_FilterBox"
AutoWordSelection="True"
Grid.Column="1"
Margin="0,1,0,1"
VerticalAlignment="Center"
Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:FilterBox}}, Path=FilterText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock x:Name="PART_Header"
Text="{TemplateBinding Header}"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="2,0,0,0"
Grid.Column="1"
IsHitTestVisible="False"/>
<Button x:Name="PART_ClearButton"
Grid.Column="2"
Margin="0,0,4,0"
Style="{StaticResource ClearButtonStyle}"
Visibility="Collapsed"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

12
ExtendedWPFToolkitSolution/Src/Xceed.Wpf.Toolkit/Xceed.Wpf.Toolkit.csproj

@ -62,6 +62,14 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="FilterBox\Themes\Genreric.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="FilterBox\Themes\Aero2.NormalColor.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="IconButton\Themes\Aero2.NormalColor.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -391,6 +399,7 @@
<Compile Include="AutoSelectTextBox\Implementation\QueryMoveFocusEventArgs.cs" />
<Compile Include="BusyIndicator\Implementation\BusyIndicator.cs" />
<Compile Include="BusyIndicator\Implementation\Converters\ProgressBarWidthConverter.cs" />
<Compile Include="FilterBox\Implementation\FilterBox.cs" />
<Compile Include="ColorPicker\Implementation\ColorPickerTabItem.cs" />
<Compile Include="Core\Converters\ColorModeToTabItemSelectedConverter.cs" />
<Compile Include="Core\LocationEnum.cs" />
@ -780,6 +789,9 @@
<ItemGroup>
<Compile Include="PropertyGrid\Implementation\Definitions\DefinitionBase.cs" />
</ItemGroup>
<ItemGroup>
<Resource Include="FilterBox\Images\icon-search.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

Loading…
Cancel
Save