Enum filter controls
For having a CheckBox selection for enum type like this
and make easy filter on collection
you can use this two components
- EnumFilterControl
- EnumFilterComboControl
EnumFilterControl
Is base control for showing enum in grid
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 |
public class EnumFilterControl : Control, INotifyPropertyChanged { #region Methods OnPropertyChanged protected void OnPropertyChanged<T>(Expression<Func<T>> expression) { var property = (MemberExpression)expression.Body; this.OnPropertyChanged(property.Member.Name); } //public void OnPropertyChanged(string name) //{ // this.OnPropertyChanged(this, new PropertyChangedEventArgs(name)); //} public void OnPropertyChanged([CallerMemberName] string propertyName = null) { this.OnPropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } protected virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs args) { if (PropertyChanged != null ) { PropertyChanged(sender, args); } //OnDirty(sender, args); } public void Raise(string propertyName) { OnPropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } public event PropertyChangedEventHandler PropertyChanged; #endregion #region Constructor & OnApplyTemplate static EnumFilterControl() { DefaultStyleKeyProperty.OverrideMetadata(typeof(EnumFilterControl), new FrameworkPropertyMetadata(typeof(EnumFilterControl))); } public EnumFilterControl() { Items.PropertyChanged += (ss, ee) => { Update(); }; } public override void OnApplyTemplate() { base.OnApplyTemplate(); // rempliassage des items issu du type UpdateType(); } #endregion bool isTypeUpdated = false; private void UpdateType() { if (isTypeUpdated) return; if (_type != null) { isTypeUpdated = true; Items.Clear(); HideFilterColorAttribute[] hfca = _type.GetCustomAttributes(typeof(HideFilterColorAttribute), false) as HideFilterColorAttribute[]; if (ShowColor) { // case when enum has HideFilterColorAttribute if (hfca.Length != 0) ShowColor = false; // check color converter // check itemsconverter is set (cannot check if brush type is possible) if(ItemConverter == null) { // return false if enum has no typeconverter or typeconvert cannot convert to brush TypeConverter tc = TypeDescriptor.GetConverter(_type); if (tc == null) ShowColor = false; else ShowColor = tc.CanConvertTo(typeof(Brush)); } } foreach (var item in Enum.GetValues(_type)) { var memInfo = _type.GetMember(item.ToString()); var ex = memInfo[0].GetCustomAttributes(typeof(ExcludeFilterAttribute), false); if (ShowHiddenEnum || ex.Length == 0) { Items.Add(new EnumFilterItem(this, item, true)); } } // ici on peut rajouter des items ou en enlever InsertSpecificItems(); // mise a jour de la selection en fonction de la selection initial // masquage notification FromSelector(); Update(); } } protected virtual void ItemsUpdated() { } private object _selector = null; private Type _type = null; public void FromSelector() { this.canNotify = false; foreach (var item in Items) { item.IsChecked = false; } UpdateType(); if (_selector == null) { foreach (var item in Items) { item.IsChecked = true; } Selector = ToSelector(); } else if (_selector is object[]) { object[] tbl = _selector as object[]; foreach (var item in Items) { if (tbl.Contains(item.Item)) item.IsChecked = true; } } Update(true); this.canNotify = true; } public object[] ToSelector() { List<object> list = new List<object>(); bool all = true; foreach (var item in Items) { if (item.Item != null) { if (item.IsChecked) list.Add(item.Item); else all = false; } } if (all) return null; else return list.ToArray(); } #region Changed Functions private bool canNotify = false; private static void AllChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (e.NewValue.Equals(true)) { EnumFilterControl efc = d as EnumFilterControl; if (!efc.canNotify) return; efc.canNotify = false; efc.Set(true); efc.canNotify = true; efc.Update(); } } private static void NoneChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (e.NewValue.Equals(true)) { EnumFilterControl efc = d as EnumFilterControl; if (!efc.canNotify) return; efc.canNotify = false; efc.Set(false); efc.canNotify = true; efc.Update(); } } private static void Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { EnumFilterControl msf = d as EnumFilterControl; if (!msf.canNotify) return; msf.canNotify = false; msf.Update(); msf.canNotify = true; } private void Set(bool value) { foreach (var item in Items) { item.IsChecked = value; } } private void Update(bool force = false) { if (!force && !canNotify) return; bool ALL = true; bool NONE = true; foreach (var item in Items) { if (item.Item != null) { if (!item.IsChecked) ALL = false; if (item.IsChecked) NONE = false; } } All = ALL; None = NONE; AllowAll = !ALL; AllowNone = !NONE; if (!force) { if(Items.Count != 0) Selector = ToSelector(); ItemsUpdated(); } } #endregion #region Dependency Properties #region Title (DP SHORT) public object Title { get { return (object)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } public static readonly DependencyProperty TitleProperty = DependencyProperty.Register( "Title", typeof(object), typeof(EnumFilterControl), new PropertyMetadata("Filter")); #endregion #region ShowHiddenEnum (DP SHORT) public bool ShowHiddenEnum { get { return (bool)GetValue(ShowHiddenEnumProperty); } set { SetValue(ShowHiddenEnumProperty, value); } } public static readonly DependencyProperty ShowHiddenEnumProperty = DependencyProperty.Register("ShowHiddenEnum", typeof(bool), typeof(EnumFilterControl), new PropertyMetadata(false)); #endregion #region ShowAll (DP SHORT) public bool ShowAll { get { return (bool)GetValue(ShowAllProperty); } set { SetValue(ShowAllProperty, value); } } public static readonly DependencyProperty ShowAllProperty = DependencyProperty.Register("ShowAll", typeof(bool), typeof(EnumFilterControl), new PropertyMetadata(true)); #endregion #region ShowNone (DP SHORT) public bool ShowNone { get { return (bool)GetValue(ShowNoneProperty); } set { SetValue(ShowNoneProperty, value); } } public static readonly DependencyProperty ShowNoneProperty = DependencyProperty.Register("ShowNone", typeof(bool), typeof(EnumFilterControl), new PropertyMetadata(true)); #endregion #region AllowAll (DP SHORT) public bool AllowAll { get { return (bool)GetValue(AllowAllProperty); } set { SetValue(AllowAllProperty, value); } } public static readonly DependencyProperty AllowAllProperty = DependencyProperty.Register("AllowAll", typeof(bool), typeof(EnumFilterControl), new PropertyMetadata(false)); #endregion #region AllowNone (DP SHORT) public bool AllowNone { get { return (bool)GetValue(AllowNoneProperty); } set { SetValue(AllowNoneProperty, value); } } public static readonly DependencyProperty AllowNoneProperty = DependencyProperty.Register("AllowNone", typeof(bool), typeof(EnumFilterControl), new PropertyMetadata(true)); #endregion #region All (DP SHORT) public bool All { get { return (bool)GetValue(AllProperty); } set { SetValue(AllProperty, value); } } public static readonly DependencyProperty AllProperty = DependencyProperty.Register("All", typeof(bool), typeof(EnumFilterControl), new PropertyMetadata(true, AllChanged)); #endregion #region None (DP SHORT) public bool None { get { return (bool)GetValue(NoneProperty); } set { SetValue(NoneProperty, value); } } public static readonly DependencyProperty NoneProperty = DependencyProperty.Register("None", typeof(bool), typeof(EnumFilterControl), new PropertyMetadata(false, NoneChanged)); #endregion #region CheckWidth (DP SHORT) public double CheckWidth { get { return (double)GetValue(CheckWidthProperty); } set { SetValue(CheckWidthProperty, value); } } public static readonly DependencyProperty CheckWidthProperty = DependencyProperty.Register("CheckWidth", typeof(double), typeof(EnumFilterControl), new PropertyMetadata(80D)); #endregion #region Type (DP) public Type Type { get { return (Type)GetValue(TypeProperty); } set { SetValue(TypeProperty, value); } } public static readonly DependencyProperty TypeProperty = DependencyProperty.Register("Type", typeof(Type), typeof(EnumFilterControl), new PropertyMetadata(null, TypeChanged)); private static void TypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { EnumFilterControl efc = d as EnumFilterControl; efc._type = e.NewValue as Type; } #endregion #region Selector (DP) public object Selector { get { return (object)GetValue(SelectorProperty); } set { SetValue(SelectorProperty, value); } } public static readonly DependencyProperty SelectorProperty = DependencyProperty.Register("Selector", typeof(object), typeof(EnumFilterControl), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, SelectorChanged)); private static void SelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { EnumFilterControl efc = d as EnumFilterControl; efc._selector = e.NewValue; efc.FromSelector(); } #endregion #region ShowColor (DP SHORT) public bool ShowColor { get { return (bool)GetValue(ShowColorProperty); } set { SetValue(ShowColorProperty, value); } } public static readonly DependencyProperty ShowColorProperty = DependencyProperty.Register("ShowColor", typeof(bool), typeof(EnumFilterControl), new PropertyMetadata(true)); #endregion #region AllText (DP SHORT) public string AllText { get { return (string)GetValue(AllTextProperty); } set { SetValue(AllTextProperty, value); } } public static readonly DependencyProperty AllTextProperty = DependencyProperty.Register("AllText", typeof(string), typeof(EnumFilterControl), new PropertyMetadata("All")); #endregion #region NoneText (DP SHORT) public string NoneText { get { return (string)GetValue(NoneTextProperty); } set { SetValue(NoneTextProperty, value); } } public static readonly DependencyProperty NoneTextProperty = DependencyProperty.Register("NoneText", typeof(string), typeof(EnumFilterControl), new PropertyMetadata("None")); #endregion #endregion #region OTHER Properties public IValueConverter ItemConverter { get; set; } = null; public EnumFilterItems Items { get; } = new EnumFilterItems(); #endregion protected virtual void InsertSpecificItems() { } } #region Attributes [AttributeUsage(AttributeTargets.Enum, AllowMultiple = false)] public class HideFilterColorAttribute : Attribute { } [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] public class ExcludeFilterAttribute : Attribute { } [AttributeUsage(AttributeTargets.Enum, AllowMultiple = false)] public abstract class FilterTextAttribute : Attribute { public string Name { get; private set; } public FilterTextAttribute(string name) { this.Name = name; } } public class AllFilterTextAttribute : FilterTextAttribute { public AllFilterTextAttribute(string name) : base(name) { } } public class NoneFilterTextAttribute : FilterTextAttribute { public NoneFilterTextAttribute(string name) : base(name) { } } #endregion #region EnumFilterItems & EnumFilterItem for component public class EnumFilterItems : FullObservableCollection<EnumFilterItem> { } public class EnumFilterItem : ViewModelBase { public EnumFilterControl Parent { get; private set; } public object Item { get; private set; } #region IsChecked private bool _IsChecked = false; public bool IsChecked { get { return _IsChecked; } set { _IsChecked = value; OnPropertyChanged(); } } #endregion public EnumFilterItem(EnumFilterControl parent, object item, bool isChecked) { this.Parent = parent; this.Item = item; this.IsChecked = IsChecked; } public string Text { get { IValueConverter ivc = Parent?.ItemConverter; try { if (ivc != null) { return (string)ivc.Convert(Item, typeof(string), null, null); } else { TypeConverter tc = TypeDescriptor.GetConverter(Item.GetType()); if (tc != null && tc.CanConvertTo(typeof(string))) return (string)tc.ConvertTo(Item, typeof(string)); } } catch { } return Item?.ToString(); } } public Color Color { get { return Colors.Blue; } } public Brush Brush { get { IValueConverter ivc = Parent?.ItemConverter; if (ivc != null) { return (Brush)ivc.Convert(Item, typeof(Brush), null, null); } else { if (Item == null) return Brushes.Transparent; TypeConverter tc = TypeDescriptor.GetConverter(Item.GetType()); if (tc == null || !tc.CanConvertTo(typeof(Brush))) return new SolidColorBrush(Colors.Red); else return (Brush)tc.ConvertTo(Item, typeof(Brush)); } } } } public abstract class ExcludeFilterItem : EnumFilterItem { public ExcludeFilterItem(EnumFilterControl parent, bool isChecked) : base(parent, null, isChecked) { } public ExcludeFilterItem() : this(null, false) { } } public class AllFilterItem : ExcludeFilterItem { public AllFilterItem() : base() { } public AllFilterItem(EnumFilterControl parent, bool isChecked) : base(parent, isChecked) { } } public class NoneFilterItem : ExcludeFilterItem { public NoneFilterItem() : base() { } public NoneFilterItem(EnumFilterControl parent, bool isChecked) : base(parent, isChecked) { } } #endregion public class BoolEnumFilterConverter : MarkupExtension, IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => (bool)value ? Visibility.Visible : Visibility.Collapsed; public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException(); public override object ProvideValue(IServiceProvider serviceProvider) => this; } |
EnumFilterComboControl
Is the same control but using ComboBox
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
public class EnumFilterComboControl : EnumFilterControl { static EnumFilterComboControl() { DefaultStyleKeyProperty.OverrideMetadata(typeof(EnumFilterComboControl), new FrameworkPropertyMetadata(typeof(EnumFilterComboControl))); } protected override void InsertSpecificItems() { base.InsertSpecificItems(); if (ShowAll) this.Items.Insert(0, new AllFilterItem(this, true)); if (ShowNone) this.Items.Add(new NoneFilterItem(this, true)); this.SelectedItem = this.Items[0]; } #region SelectedItem private object _SelectedItem = null; public object SelectedItem { get { return _SelectedItem; } set { _SelectedItem = value; OnPropertyChanged(); } } #endregion protected override void ItemsUpdated() { base.ItemsUpdated(); OnPropertyChanged("SelectionObject"); } public object SelectionObject { get { if (All) return AllText; else if (None) return NoneText; // TypeConverter tc = TypeDescriptor.GetConverter(Type); // color if (this.ShowColor) { ColorItems ci = new ColorItems(); foreach (var item in Items) { if (item.Item != null) { if (item.IsChecked) { Brush b = null; if (ItemConverter != null) b = ItemConverter.Convert(item.Item, typeof(Brush), null, null) as Brush; else if (tc != null && tc.CanConvertTo(typeof(Brush))) b = tc.ConvertTo(item.Item, typeof(Brush)) as Brush; else b = Brushes.Red; ci.Add(new ColorItem { Brush = b }); } } } return ci; } //string else { string s = ""; foreach (var item in Items) { if (item.Item != null) { if (item.IsChecked) { if (!string.IsNullOrEmpty(s)) s += ","; if (ItemConverter != null) s += ItemConverter.Convert(item.Item, typeof(string), null, null); else if (tc != null && tc.CanConvertTo(typeof(string))) s += tc.ConvertTo(item.Item, typeof(string)); else s += item.Item.ToString(); } } } return s; } //return "UNKNOW"; } } } public class ColorItems : List<ColorItem> { } public class ColorItem { public Brush Brush { get; set; } } |
Extra code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
namespace UltimateCorp.WPF.Common { public enum CollectionAction { FromItem, FromCollection, Add, Move, Remove, Set, Clear, } public delegate void FullCollectionChangedEventHandler(object sender, FullCollectionChangedEventArgs e); /// <summary> /// Class herited from PropertyChangedEventArgs including new properties and methods to handle all element changement of a Collection /// </summary> public class FullCollectionChangedEventArgs : PropertyChangedEventArgs { public CollectionAction Action { get; private set; } public IList NewItems { get; private set; } public IList OldItems { get; private set; } public int NewStartingIndex { get; private set; } public int OldStartingIndex { get; private set; } /// <summary> /// Methods that check if it is an action /// </summary> /// <param name="action">action to check</param> /// <returns>true or false</returns> public bool IsAction(CollectionAction action) { if (action == CollectionAction.FromCollection) return Action != CollectionAction.FromItem; else return Action == action; } public FullCollectionChangedEventArgs(string propertyName, CollectionAction action) : this(propertyName, action, null, null, -1, -1) { } public FullCollectionChangedEventArgs(string propertyName, CollectionAction action, IList newItems, IList oldItems) : this(propertyName, action, newItems, oldItems, -1, -1) { } /// <summary> /// Constructor /// </summary> public FullCollectionChangedEventArgs(string propertyName, CollectionAction action, IList newItems, IList oldItems, int newStartingIndex, int oldStartingIndex) : base(propertyName) { Action = action; NewItems = newItems; OldItems = oldItems; NewStartingIndex = newStartingIndex; OldStartingIndex = oldStartingIndex; } /// <summary> /// Methods that notify if a collection changed /// </summary> /// <returns>The Arg that changed</returns> public NotifyCollectionChangedEventArgs ToNotifyCollectionChangedEventArgs() { if (IsAction(CollectionAction.FromCollection)) { switch (Action) { case CollectionAction.Add: return new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, NewItems); case CollectionAction.Move: return new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, NewItems, NewStartingIndex, OldStartingIndex); case CollectionAction.Remove: return new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, OldItems); case CollectionAction.Set: return new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, NewItems, OldItems, NewStartingIndex); case CollectionAction.Clear: default: return new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); } } else { return null; } } } /// <summary> /// New class herited from ObservableCollection that can be full observed /// </summary> /// <typeparam name="T"></typeparam> public class FullObservableCollection<T> : ObservableCollection<T> { private const string COUNT = "Count"; private const string ITEM = "Item"; private const string ORDER = "Order"; public new event FullCollectionChangedEventHandler PropertyChanged; /// <summary> /// Notify if an item of the collection has changed /// </summary> /// <param name="sender">Object that send the notif</param> /// <param name="args">Arguments</param> protected virtual void OnPropertyChangedExtend(object sender, PropertyChangedEventArgs args) { if (PropertyChanged != null) { if (args is FullCollectionChangedEventArgs) PropertyChanged(sender, args as FullCollectionChangedEventArgs); else PropertyChanged(sender, new FullCollectionChangedEventArgs(args.PropertyName, CollectionAction.FromItem, null, null)); } } /// <summary> /// Override method of ClearItem() /// </summary> protected override void ClearItems() { List<T> oldItems = base.Items.ToList<T>(); foreach (var old in base.Items) { if (old is INotifyPropertyChanged) ((INotifyPropertyChanged)old).PropertyChanged -= OnPropertyChangedExtend; } base.ClearItems(); OnPropertyChangedExtend(this, new FullCollectionChangedEventArgs(COUNT, CollectionAction.Clear, null, oldItems, -1, 0)); } /// <summary> /// Override method of InsertItem /// </summary> /// <param name="index">Insert at index</param> /// <param name="item">Insert item of type T</param> protected override void InsertItem(int index, T item) { base.InsertItem(index, item); if (item is INotifyPropertyChanged) ((INotifyPropertyChanged)item).PropertyChanged += OnPropertyChangedExtend; OnPropertyChangedExtend(this, new FullCollectionChangedEventArgs(COUNT, CollectionAction.Add, new List<T>() { item }, null, index, -1)); } /// <summary> /// Override method of RemoveItem /// </summary> /// <param name="index">Remove at index</param> protected override void RemoveItem(int index) { var old = base[index]; if (old is INotifyPropertyChanged) ((INotifyPropertyChanged)old).PropertyChanged -= OnPropertyChangedExtend; base.RemoveItem(index); OnPropertyChangedExtend(this, new FullCollectionChangedEventArgs(COUNT, CollectionAction.Remove, null, new List<T>() { old }, -1, index)); } /// <summary> /// Override method of SetItem /// </summary> /// <param name="index">Set item at index</param> /// <param name="item">Item to set of type T</param> protected override void SetItem(int index, T item) { var old = base[index]; if (old is INotifyPropertyChanged) ((INotifyPropertyChanged)old).PropertyChanged -= OnPropertyChangedExtend; base.SetItem(index, item); if (item is INotifyPropertyChanged) ((INotifyPropertyChanged)item).PropertyChanged += OnPropertyChangedExtend; OnPropertyChangedExtend(this, new FullCollectionChangedEventArgs(ITEM, CollectionAction.Set, new List<T>() { item }, new List<T>() { old }, index, index)); } /// <summary> /// Override Method of MoveItem /// </summary> /// <param name="oldIndex">Item of 'oldIndex' to move</param> /// <param name="newIndex">New position</param> protected override void MoveItem(int oldIndex, int newIndex) { var old = base[oldIndex]; base.MoveItem(oldIndex, newIndex); OnPropertyChangedExtend(this, new FullCollectionChangedEventArgs(ORDER, CollectionAction.Move, null, null, newIndex, oldIndex)); } } } |
Styles
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
<!-- COLORS --> <SolidColorBrush x:Key="ALL_COLOR_ICON">white</SolidColorBrush> <SolidColorBrush x:Key="NONE_COLOR_ICON">white</SolidColorBrush> <!-- DATATEMPLATE --> <DataTemplate DataType="{x:Type local:EnumFilterItem}"> <DockPanel> <Border Background="{Binding Brush}" DockPanel.Dock="Left" Height="16" Width="16" Visibility="{Binding ShowColor, Converter={local:BoolEnumFilterConverter}, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:EnumFilterControl}}}" CornerRadius="2" VerticalAlignment="Center" Margin="1 1 0 0" /> <Border Margin="1 1 0 0" Background="Transparent"> <CheckBox Content="{Binding Text}" Width="{Binding CheckWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:EnumFilterControl}}}" IsChecked="{Binding IsChecked}" /> </Border> </DockPanel> </DataTemplate> <DataTemplate DataType="{x:Type local:AllFilterItem}"> <DockPanel> <Border Height="16" Width="16" DockPanel.Dock="Left" Visibility="{Binding ShowColor, Converter={local:BoolEnumFilterConverter}, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:EnumFilterControl}}}" Background="{Binding Brush}" Margin="1 1 0 0"> <TextBlock Text="a" FontFamily="Marlett" FontWeight="Bold" Foreground="{StaticResource ALL_COLOR_ICON}" FontSize="16" VerticalAlignment="Center" /> </Border> <CheckBox Content="{Binding AllText, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:EnumFilterControl}}}" IsChecked="{Binding All, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:EnumFilterControl}}}" Width="{Binding CheckWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:EnumFilterControl}}}" IsEnabled="{Binding AllowAll, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:EnumFilterControl}}}" Margin="1 1 0 0" HorizontalAlignment="Left" /> </DockPanel> </DataTemplate> <DataTemplate DataType="{x:Type local:NoneFilterItem}"> <DockPanel> <Border Height="16" Width="16" DockPanel.Dock="Left" Background="{Binding Brush}" Visibility="{Binding ShowColor, Converter={local:BoolEnumFilterConverter}, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:EnumFilterControl}}}" Margin="1 1 0 0"> <TextBlock Text="r" FontFamily="Marlett" Foreground="{StaticResource NONE_COLOR_ICON}" FontWeight="Bold" FontSize="16" VerticalAlignment="Center" /> </Border> <CheckBox Content="{Binding NoneText, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:EnumFilterControl}}}" IsChecked="{Binding None, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:EnumFilterControl}}}" Width="{Binding CheckWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:EnumFilterControl}}}" IsEnabled="{Binding AllowNone, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:EnumFilterControl}}}" Margin="1 1 0 0" HorizontalAlignment="Left" /> </DockPanel> </DataTemplate> <!-- EnumFilterControl --> <Style TargetType="{x:Type local:EnumFilterControl}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:EnumFilterControl}"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <DockPanel DockPanel.Dock="Top" Margin="0 1 0 1"> <ContentControl VerticalAlignment="top" Margin="0 2 0 0" Content="{TemplateBinding Title}" TextBlock.FontWeight="Bold" DockPanel.Dock="Left" /> <!--<TextBlock Text="Filtre" Margin="0 2 0 0" DockPanel.Dock="Left" FontWeight="Bold" />--> <ItemsControl DockPanel.Dock="Top" Margin="4 0 0 0"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapPanel /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ContentControl Visibility="{Binding ShowAll, Converter={local:BoolEnumFilterConverter}, RelativeSource={RelativeSource TemplatedParent}}"> <local:AllFilterItem /> </ContentControl> <ContentControl Visibility="{Binding ShowNone, Converter={local:BoolEnumFilterConverter}, RelativeSource={RelativeSource TemplatedParent}}"> <local:NoneFilterItem /> </ContentControl> </ItemsControl> <ItemsControl Margin="4 0 0 0" ItemsSource="{Binding Items, RelativeSource={RelativeSource TemplatedParent}}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapPanel /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl> </DockPanel> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- EnumFilterComboControl --> <Style TargetType="{x:Type local:EnumFilterComboControl}"> <Style.Resources> <Style TargetType="{x:Type ComboBoxItem}" BasedOn="{StaticResource {x:Type ComboBoxItem}}"> <Setter Property="OverridesDefaultStyle" Value="true" /> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> <Setter Property="Background" Value="Transparent" /> </Style > <!-- DATA TEMPLATE --> <DataTemplate x:Key="NormalItemTemplate"> <ContentControl Content="{Binding .}" /> </DataTemplate> <DataTemplate x:Key="SelectionBoxTemplate"> <StackPanel Orientation="Horizontal"> <ContentControl Content="{Binding SelectionObject, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:EnumFilterComboControl}}}" /> </StackPanel> </DataTemplate> <DataTemplate x:Key="CombinedTemplate"> <ContentPresenter x:Name="Presenter" Content="{Binding}" ContentTemplate="{StaticResource NormalItemTemplate}" /> <DataTemplate.Triggers> <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor,ComboBoxItem,1}}" Value="{x:Null}"> <Setter TargetName="Presenter" Property="ContentTemplate" Value="{StaticResource SelectionBoxTemplate}" /> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> <!-- DT for Type--> <DataTemplate DataType="{x:Type local:ColorItems}"> <ItemsControl ItemsSource="{Binding .}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl> </DataTemplate> <DataTemplate DataType="{x:Type local:ColorItem}"> <Border Background="{Binding Brush}" Height="16" Width="16" CornerRadius="2" VerticalAlignment="Center" Margin="1 1 0 0" /> </DataTemplate> <DataTemplate DataType="{x:Type local:EnumFilterItem}"> <DockPanel> <Border Background="{Binding Brush}" DockPanel.Dock="Left" Height="16" Width="16" Visibility="{Binding ShowColor, Converter={local:BoolEnumFilterConverter}, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:EnumFilterControl}}}" CornerRadius="2" VerticalAlignment="Center" Margin="1 1 0 0" /> <CheckBox Content="{Binding Text}" IsChecked="{Binding IsChecked}" Margin="1 1 0 0" HorizontalAlignment="Stretch" /> </DockPanel> </DataTemplate> </Style.Resources> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:EnumFilterComboControl}"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <Border.Resources> <!--<Style TargetType="{x:Type ContentPresenter}"> <Setter Property="HorizontalAlignment" Value="Stretch" /> </Style>--> </Border.Resources> <DockPanel DockPanel.Dock="Top" Margin="0 1 0 1"> <ContentControl VerticalAlignment="Center" Content="{TemplateBinding Title}" TextBlock.FontWeight="Bold" DockPanel.Dock="Left" /> <ComboBox Margin="4 0 0 0" ItemsSource="{Binding Items, RelativeSource={RelativeSource TemplatedParent}}" SelectedItem="{Binding SelectedItem, RelativeSource={RelativeSource TemplatedParent}}" ItemTemplate="{StaticResource CombinedTemplate}" HorizontalContentAlignment="Stretch"> <ComboBox.Resources> <SolidColorBrush x:Key="AccentColorBrush2" Color="Transparent" /> <SolidColorBrush x:Key="AccentColorBrush3" Color="Transparent" /> <SolidColorBrush x:Key="AccentColorBrush" Color="Transparent" /> </ComboBox.Resources> </ComboBox> </DockPanel> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> |
Common properties
Properties | Descriptions | Default |
---|---|---|
Title | Title for control (show at left) | Filter |
ShowHiddenEnum | Define if you must show item of enum with ExcludeFilterAttribute | false |
if you have an enum with (usage of attribues)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[Flags] [TypeConverter(typeof(LogLevelTypeConverter))] public enum LogLevel : int { [ExcludeFilter] None = 0x00, Info = 0x01, Alert = 0x02, Error = 0x04, Debug = 0x08, Critical = 0x10, [ExcludeFilter] All = Info | Alert | Error | Debug | Critical, } |
in this case when ShowHiddenEnum=true, you can show None and All
And if you use HideFilterColorAttribute on enum like this
1 2 3 4 5 6 |
[Flags] [HideFilterColor] public enum LogLevel : int { .... } |
Force to hide color even ShowColor=true
Properties | Descriptions | Default |
---|---|---|
ItemConverter | For specify class can convert Items (IValueConverter) for color indicator and text translation or try to use TypeConverter | null |
TypeConverter if define, like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
public class LogLevelConverter : MarkupExtension, IValueConverter { public override object ProvideValue(IServiceProvider serviceProvider) { return this; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { string s = ((string)parameter ?? ""); if (value == null) { return null; } LogLevel ll = (LogLevel)value; if (targetType.Equals(typeof(Brush)) || s.Contains("color")) { Color c = Colors.Black; switch (ll) { case LogLevel.Info: c = Colors.Blue; break; case LogLevel.Alert: c = Colors.Orange; break; case LogLevel.Error: c = Colors.Red; break; case LogLevel.Debug: c = Colors.DarkViolet; break; case LogLevel.Critical: c = Colors.DarkRed; break; } return new SolidColorBrush(c); } else if (targetType.Equals(typeof(Brush)) || s.Contains("rsc")) { string icn = "appbar_location_circle"; switch (ll) { case LogLevel.Info: icn = "appbar_info_circle"; break; case LogLevel.Alert: icn = "appbar_alert_circle"; break; case LogLevel.Error: icn = "appbar_error_circle"; break; case LogLevel.Debug: icn = "appbar_debug_circle"; break; case LogLevel.Critical: icn = "appbar_critical_circle"; break; case LogLevel.None: return null; } return icn; } var enumValue = (LogLevel)value; var result = new List<object>( Enum.GetValues(typeof(LogLevel)) .Cast<LogLevel>() .Where(c => enumValue.HasFlag(c) && c != 0) .Cast<object>()); return result; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { var result = new LogLevel(); var list = value as List<object>; if (list != null && list.Count > 0) { list.ForEach((c) => { result = result | (LogLevel)c; }); } return result; } } |
usage like this
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<StackPanel.Resources> <local:LogLevelConverter x:Key="llc" /> </StackPanel.Resources> .......... <EnumFilterComboControl DockPanel.Dock="Right" Margin="0 -1 15 0" Type="{x:Type local:LogLevel}" ItemConverter="{StaticResource llc}" Selector="{Binding Selector, Mode=TwoWay}" Width="150" MinHeight="10" Height="28" VerticalAlignment="Center"/> |
or use a TypeConverter like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
[TypeConverter(typeof(ContactesStatConverter))] public enum ContactesStat { PreSuscrib = 0, Suscrib = 1, UnSuscrib = 2, Reject = 3, } public class ContactesStatConverter : TypeConverter { public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { if (destinationType.Equals(typeof(string))) return true; if (destinationType.Equals(typeof(Brush))) return true; return base.CanConvertTo(context, destinationType); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType.Equals(typeof(string))) { switch (((ContactesStat)value)) { case ContactesStat.PreSuscrib: return "Préinscription"; case ContactesStat.Suscrib: return "Inscrit"; case ContactesStat.UnSuscrib: return "Désinscrit"; case ContactesStat.Reject: return "Rejeté"; default: return "Inconnu"; } } if (destinationType.Equals(typeof(Brush))) { switch (((ContactesStat)value)) { case ContactesStat.PreSuscrib: return Brushes.Aqua; case ContactesStat.Suscrib: return Brushes.Lime; case ContactesStat.UnSuscrib: return Brushes.Orange; case ContactesStat.Reject: return Brushes.Red; default: return "Inconnu"; } } return base.ConvertTo(context, culture, value, destinationType); } } |
for TypeConverter the converting is automatic
Properties | Descriptions | Default |
---|---|---|
ShowColor | define if rectangle color is visible and ItemsConverter is define for color (not return null) or TypeConverter exist and can convert to Brush | true |
ShowAll | Show All CheckBox | true |
ShowNone | Show None CheckBox | true |
AllText | Text for All CheckBox | true |
NoneText | Text for None CheckBox | true |
Selector | Is the selectedItems for this component with
|
null |
AllowAll | do not use, is used for disable all checkbox | |
AllowNone | do not use, is used for disable none checkbox | |
All | do not use, is used for check all checkbox | |
None | do not use, is used for checknone checkbox | |
CheckWith | for specify size of CheckBox if you want | 80D |
Type | Is the type of enum you want to show | null |
Usage
in xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<local:EnumFilterControl DockPanel.Dock="top" Margin="0" Title="Value to show" ShowAll="true" ShowNone="true" CheckWidth="150" Type="{x:Type local:ContactesStat}" Selector="{Binding Selector, Mode=TwoWay}" Height="100" ShowColor="false" VerticalAlignment="Center" /> <local:EnumFilterComboControl DockPanel.Dock="top" Margin="0" ShowAll="true" ShowNone="true" Type="{x:Type local:ContactesStat}" Selector="{Binding Selector, Mode=TwoWay}" Width="400" ShowColor="false" VerticalAlignment="Center" /> <local:EnumFilterComboControl DockPanel.Dock="top" Margin="0 100 0 0" ShowAll="true" ShowNone="true" Type="{x:Type local:ContactesStat}" Selector="{Binding Selector, Mode=TwoWay}" Width="400" ShowColor="true" VerticalAlignment="Center" /> |
for filtering
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#region Selector private object[] _Selector = null; public object[] Selector { get => _Selector; set { _Selector = value; OnPropertyChanged(); ICollectionView ic = CollectionViewSource.GetDefaultView(Contactes); if (_Selector == null) ic.Filter = null; else if (_Selector.Length == 0) ic.Filter = x => false; else ic.Filter = x => Selector.Contains((x as contactes).Stat); } } #endregion |
Categories: Non classé
Commentaires récents