using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Reflection; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using DTS.Common.Controls; using DTS.Common.Interface.RegionOfInterest.RegionOfInterestChannels; using DTS.Common.Utils; namespace RegionOfInterestChannels { public static class GridViewColumns { [AttachedPropertyBrowsableForType(typeof(GridView))] public static object GetColumnsSource(DependencyObject obj) { return obj.GetValue(ColumnsSourceProperty); } public static void SetColumnsSource(DependencyObject obj, object value) { obj.SetValue(ColumnsSourceProperty, value); } // Using a DependencyProperty as the backing store for ColumnsSource. This enables animation, styling, binding, etc... public static readonly DependencyProperty ColumnsSourceProperty = DependencyProperty.RegisterAttached( "ColumnsSource", typeof(object), typeof(GridViewColumns), new UIPropertyMetadata( null, ColumnsSourceChanged)); [AttachedPropertyBrowsableForType(typeof(GridView))] public static DataTemplateSelector GetCellDataTemplateSelector(DependencyObject obj) { return (DataTemplateSelector)obj.GetValue(CellDataTemplateSelectorProperty); } public static void SetCellDataTemplateSelector(DependencyObject obj, DataTemplateSelector value) { obj.SetValue(CellDataTemplateSelectorProperty, value); } public static readonly DependencyProperty CellDataTemplateSelectorProperty = DependencyProperty.RegisterAttached( "CellDataTemplateSelector", typeof(DataTemplateSelector), typeof(GridViewColumns), new UIPropertyMetadata(null)); [AttachedPropertyBrowsableForType(typeof(GridView))] public static DataTemplate GetCellDataTemplate(DependencyObject obj) { return (DataTemplate)obj.GetValue(CellDataTemplateProperty); } public static void SetCellDataTemplate(DependencyObject obj, DataTemplate value) { obj.SetValue(CellDataTemplateProperty, value); } public static readonly DependencyProperty CellDataTemplateProperty = DependencyProperty.RegisterAttached( "CellDataTemplate", typeof(DataTemplate), typeof(GridViewColumns), new UIPropertyMetadata(null)); [AttachedPropertyBrowsableForType(typeof(GridView))] public static string GetHeaderTextMember(DependencyObject obj) { return (string)obj.GetValue(HeaderTextMemberProperty); } public static void SetHeaderTextMember(DependencyObject obj, string value) { obj.SetValue(HeaderTextMemberProperty, value); } // Using a DependencyProperty as the backing store for HeaderTextMember. This enables animation, styling, binding, etc... public static readonly DependencyProperty HeaderTextMemberProperty = DependencyProperty.RegisterAttached("HeaderTextMember", typeof(string), typeof(GridViewColumns), new UIPropertyMetadata(null)); [AttachedPropertyBrowsableForType(typeof(GridView))] public static string GetDisplayMember(DependencyObject obj) { return (string)obj.GetValue(DisplayMemberProperty); } public static void SetDisplayMember(DependencyObject obj, string value) { obj.SetValue(DisplayMemberProperty, value); } // Using a DependencyProperty as the backing store for DisplayMember. This enables animation, styling, binding, etc... public static readonly DependencyProperty DisplayMemberProperty = DependencyProperty.RegisterAttached("DisplayMember", typeof(string), typeof(GridViewColumns), new UIPropertyMetadata(null)); private static void ColumnsSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { GridView gridView = obj as GridView; if (gridView != null) { gridView.Columns.Clear(); if (e.OldValue != null) { ICollectionView view = CollectionViewSource.GetDefaultView(e.OldValue); if (view != null) RemoveHandlers(gridView, view); } if (e.NewValue != null) { ICollectionView view = CollectionViewSource.GetDefaultView(e.NewValue); if (view != null) { AddHandlers(gridView, view); CreateColumns(gridView, view); } } } } private static IDictionary> _gridViewsByColumnsSource = new Dictionary>(); private static List GetGridViewsForColumnSource(ICollectionView columnSource) { List gridViews; if (!_gridViewsByColumnsSource.TryGetValue(columnSource, out gridViews)) { gridViews = new List(); _gridViewsByColumnsSource.Add(columnSource, gridViews); } return gridViews; } private static void AddHandlers(GridView gridView, ICollectionView view) { GetGridViewsForColumnSource(view).Add(gridView); view.CollectionChanged += ColumnsSource_CollectionChanged; } private static void CreateColumns(GridView gridView, ICollectionView view) { foreach (var item in view) { GridViewColumn column = CreateColumn(gridView, item); gridView.Columns.Add(column); } } private static void RemoveHandlers(GridView gridView, ICollectionView view) { view.CollectionChanged -= ColumnsSource_CollectionChanged; GetGridViewsForColumnSource(view).Remove(gridView); } private static void ColumnsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { ICollectionView view = sender as ICollectionView; var gridViews = GetGridViewsForColumnSource(view); if (gridViews == null || gridViews.Count == 0) return; switch (e.Action) { case NotifyCollectionChangedAction.Add: foreach (var gridView in gridViews) { for (int i = 0; i < e.NewItems.Count; i++) { GridViewColumn column = CreateColumn(gridView, e.NewItems[i]); gridView.Columns.Insert(e.NewStartingIndex + i, column); } } break; case NotifyCollectionChangedAction.Move: foreach (var gridView in gridViews) { List columns = new List(); for (int i = 0; i < e.OldItems.Count; i++) { GridViewColumn column = gridView.Columns[e.OldStartingIndex + i]; columns.Add(column); } for (int i = 0; i < e.NewItems.Count; i++) { GridViewColumn column = columns[i]; gridView.Columns.Insert(e.NewStartingIndex + i, column); } } break; case NotifyCollectionChangedAction.Remove: foreach (var gridView in gridViews) { for (int i = 0; i < e.OldItems.Count; i++) { gridView.Columns.RemoveAt(e.OldStartingIndex); } } break; case NotifyCollectionChangedAction.Replace: foreach (var gridView in gridViews) { for (int i = 0; i < e.NewItems.Count; i++) { GridViewColumn column = CreateColumn(gridView, e.NewItems[i]); gridView.Columns[e.NewStartingIndex + i] = column; } } break; case NotifyCollectionChangedAction.Reset: foreach (var gridView in gridViews) { gridView.Columns.Clear(); CreateColumns(gridView, sender as ICollectionView); } break; default: break; } } private static void GridViewColumnHeaderSearchable_OnSearch(object sender, RoutedEventArgs e) { var searchTerm = (string)e.OriginalSource; var columnTag = (sender as GridViewColumnHeaderSearchable)?.Tag; var viewModel = (IRegionOfInterestChannelsViewModel)(sender as GridViewColumnHeaderSearchable)?.DataContext; viewModel?.Filter(columnTag, searchTerm); } private static void GridViewColumnHeader_OnClick(object sender, RoutedEventArgs e) { var columnTag = (sender as GridViewColumnHeaderSearchable)?.Tag ?? Utils.FindChild((DependencyObject)e.OriginalSource, null)?.Tag; var viewModel = (IRegionOfInterestChannelsViewModel)(sender as GridViewColumnHeaderSearchable)?.DataContext; viewModel?.Sort(columnTag, true); } private static void GridViewColumnHeaderSelectable_OnSelectAll(object sender, RoutedEventArgs e) { var columnTag = (sender as GridViewColumnHeaderSelectable)?.Tag.ToString(); var columnIndex = GetArrayIndex(columnTag); var viewModel = (IRegionOfInterestChannelsViewModel)(sender as GridViewColumnHeaderSelectable)?.DataContext; viewModel?.SelectAll(columnIndex, (bool)(e?.OriginalSource ?? false)); } private static GridViewColumn CreateColumn(GridView gridView, object columnSource) { GridViewColumn column = new GridViewColumn(); string headerTextMember = GetHeaderTextMember(gridView); string displayMember = GetDisplayMember(gridView); DataTemplate template = GetCellDataTemplate(gridView); DataTemplateSelector selector = GetCellDataTemplateSelector(gridView); if (!string.IsNullOrEmpty(headerTextMember)) { var columnSourceType = (System.Type)GetPropertyValue(columnSource, "MemberType"); switch (true) { case bool _ when columnSourceType == typeof(bool): column.Header = new GridViewColumnHeaderSelectable { HeaderTitle = (string)GetPropertyValue(columnSource, headerTextMember), Tag = (string)GetPropertyValue(columnSource, displayMember), }; ((GridViewColumnHeaderSelectable)column.Header).SelectAll += GridViewColumnHeaderSelectable_OnSelectAll; break; case bool _ when columnSourceType == typeof(string): column.Header = new GridViewColumnHeaderSearchable { HeaderTitle = (string)GetPropertyValue(columnSource, headerTextMember), Tag = (string)GetPropertyValue(columnSource, displayMember), }; ((GridViewColumnHeaderSearchable)column.Header).Search += GridViewColumnHeaderSearchable_OnSearch; ((GridViewColumnHeaderSearchable)column.Header).ClickHandler += GridViewColumnHeader_OnClick; break; default: column.Header = (string)GetPropertyValue(columnSource, headerTextMember); break; } //column.Header = GetPropertyValue(columnSource, headerTextMember); } //remember, remember: selector < template < displaymember if (null != selector) { column.CellTemplateSelector = selector; } if (null != template) { column.CellTemplate = template; } if (!string.IsNullOrEmpty(displayMember)) { //string propertyName = GetPropertyValue(columnSource, displayMember) as string; //column.DisplayMemberBinding = new Binding(propertyName); } return column; } private static object GetPropertyValue(object obj, string propertyName) { if (obj != null) { PropertyInfo prop = obj.GetType().GetProperty(propertyName); if (prop != null) return prop.GetValue(obj, null); } return null; } private static int GetArrayIndex(string fromString) { var openBracket = fromString.LastIndexOf("["); var closeBracket = fromString.LastIndexOf("]"); var numString = fromString.Substring(openBracket + 1, closeBracket - openBracket - 1); if (int.TryParse(numString, out var index)) { return index; } return -1; } } }