private void UpdateView(IEnumerable value) { // NOTE : We need to clear the SortDescription before // clearing the InnerGrid.Columns so that the Adorners // are appropriately cleared. InnerListColumn sortedColumn = this.SortedColumn; this.ClearSort(); // Release the current inner grid \\ this.ReleaseInnerGridReferences(); if (this.AutoGenerateColumns) { this.innerGrid = new InnerListGridView(); // PopulateColumns deals with a null newEnumerable this.innerGrid.PopulateColumns(value); } else { this.innerGrid = new InnerListGridView(this.Columns); } this.View = this.innerGrid; this.SetColumnHeaderActions(); if (sortedColumn != null && this.Columns.Contains(sortedColumn)) { this.ApplySort(sortedColumn, false); } }
/// <summary> /// Adds the specified columns, and optionally default filter and search rules. /// </summary> /// <param name="column">The column to add.</param> /// <param name="addDefaultFilterRules">Whether to add default filter rules for the specified column.</param> /// <exception cref="ArgumentNullException">The specified value is a null reference.</exception> public void AddColumn(InnerListColumn column, bool addDefaultFilterRules) { if (column == null) { throw new ArgumentNullException("column"); } this.List.Columns.Add(column); if (addDefaultFilterRules) { Type genericSelectorRuleType = typeof(PropertyValueSelectorFilterRule <>).MakeGenericType(column.DataDescription.DataType); ConstructorInfo selectorRuleConstructorInfo = genericSelectorRuleType.GetConstructor(new Type[] { typeof(string), typeof(string) }); SelectorFilterRule selectorRule = (SelectorFilterRule)selectorRuleConstructorInfo.Invoke(new object[] { column.DataDescription.PropertyName, column.DataDescription.DisplayName }); if (addDefaultFilterRules) { this.AddFilterRulePicker.ColumnFilterRules.Add(new AddFilterRulePickerItem(new FilterRulePanelItem(selectorRule, selectorRule.DisplayName))); } // Automatically add a search rule if the search box is shown \\ if (this.IsSearchShown) { this.SearchBox.Parser.TryAddSearchableRule <TextContainsFilterRule>(selectorRule); // Add this property to the full-text search properties \\ this.defaultFullTextSearchRule.PropertyNames.Add(column.DataDescription.PropertyName); } } }
/// <summary> /// Sorts the list by the specified column. This has no effect if the list does not have a data source. /// </summary> /// <param name="column"> /// The column to sort /// </param> /// <param name="shouldScrollIntoView"> /// Indicates whether the SelectedItem should be scrolled into view. /// </param> /// <exception cref="ArgumentNullException">The specified value is a null reference.</exception> public void ApplySort(InnerListColumn column, bool shouldScrollIntoView) { if (column == null) { throw new ArgumentNullException("column"); } // NOTE : By setting the column here, it will be used // later to set the sorted column when the UI state // is ready. this.sortedColumn = column; // If the list hasn't been populated, don't do anything \\ if (this.CollectionView == null) { return; } this.UpdatePrimarySortColumn(); using (this.CollectionView.DeferRefresh()) { ListCollectionView lcv = (ListCollectionView)this.CollectionView; lcv.CustomSort = new PropertyValueComparer(this.GetDescriptionsForSorting(), true, FilterRuleCustomizationFactory.FactoryInstance.PropertyValueGetter); } if (shouldScrollIntoView && this.SelectedIndex > 0) { this.ScrollIntoView(this.SelectedItem); } }
/// <summary> /// Remove button was clicked. /// </summary> /// <param name="sender">Remove button.</param> /// <param name="e">The RoutedEventArgs.</param> /// <remarks> /// Note that we do not attempt to maintain the ordering of items /// in the NotSelected list when they are removed and then added back. /// In the current implementation, the View of the NotSelected list is /// sorted by name through the CollectionViewSource. /// </remarks> internal void RemoveButtonClick(object sender, RoutedEventArgs e) { InnerListColumn column = (InnerListColumn)this.PART_SelectedList.SelectedItem; Debug.Assert(null != column); int selectedIndex = this.PART_SelectedList.SelectedIndex; Debug.Assert(0 <= selectedIndex); this.NotSelectedColumns.Add(column); this.SelectedColumns.Remove(column); // Without this, there is no selection after the item is removed. if (selectedIndex < this.SelectedColumns.Count) { // Select next item in Selected list // Note that we select the next item based on the index // in the View rather than the ViewModel. this.PART_SelectedList.SelectedIndex = selectedIndex; } else if (0 < selectedIndex) { // Highest-index item removed, select previous item Debug.Assert((selectedIndex - 1) < this.SelectedColumns.Count); this.PART_SelectedList.SelectedIndex = selectedIndex - 1; } // otherwise there are no more items to select // select new item in NotSelected list this.PART_NotSelectedList.SelectedItem = column; // Just to make sure, we call OnSelectionChanged // explicitly here as well. this.OnSelectionChanged(); }
/// <summary> /// Syncronizes AvailableColumns and Columns preserving the order from Columns that /// comes from the user moving Columns around. /// </summary> private void SynchronizeColumns() { this.canChangeColumns = true; try { // Add to listViewColumns all Visible columns in availableColumns not already in listViewColumns foreach (InnerListColumn column in this.AvailableColumns) { if (column.Visible && !this.Columns.Contains(column)) { this.Columns.Add(column); } } // Remove all columns which are not visible or removed from Available columns. for (int i = this.Columns.Count - 1; i >= 0; i--) { InnerListColumn listViewColumn = (InnerListColumn)this.Columns[i]; if (!listViewColumn.Visible || !this.AvailableColumns.Contains(listViewColumn)) { this.Columns.RemoveAt(i); } } } finally { this.canChangeColumns = false; } }
/// <summary> /// Called when the ItemsSource changes to auto populate the GridView columns /// with reflection information on the first element of the ItemsSource. /// </summary> /// <param name="newValue"> /// The new ItemsSource. /// This is used just to fetch .the first collection element. /// </param> internal void PopulateColumns(System.Collections.IEnumerable newValue) { if (newValue == null) { return; // No elements, so we can't populate } IEnumerator newValueEnumerator = newValue.GetEnumerator(); if (!newValueEnumerator.MoveNext()) { return; // No first element, so we can't populate } object first = newValueEnumerator.Current; if (first == null) { return; } Debug.Assert(this.AvailableColumns.Count == 0, "AvailabeColumns should be empty at this point"); PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(first); foreach (PropertyDescriptor property in properties) { UIPropertyGroupDescription dataDescription = new UIPropertyGroupDescription(property.Name, property.Name, property.PropertyType); InnerListColumn column = new InnerListColumn(dataDescription); this.AvailableColumns.Add(column); } }
/// <summary> /// Adds the specified column. /// Default filter rules for the column will be added if the filter is shown. /// A default search rule will be added if the search box is shown and the column's data type is searchable. /// </summary> /// <param name="column">The column to add.</param> /// <exception cref="ArgumentNullException">The specified value is a null reference.</exception> public void AddColumn(InnerListColumn column) { if (column == null) { throw new ArgumentNullException("column"); } this.AddColumn(column, this.IsFilterShown); }
private static ColumnStateDescriptor CreateColumnStateDescriptor(InnerListColumn ilc, bool isInUse) { ColumnStateDescriptor csd = new ColumnStateDescriptor(); csd.IsInUse = isInUse; csd.Width = GetColumnWidth(ilc); csd.SortDirection = ilc.DataDescription.SortDirection; return(csd); }
private static object WidthProperty_CoerceProperty(DependencyObject d, object baseValue) { InnerListColumn ilc = (InnerListColumn)d; if (((double)baseValue) < ilc.MinWidth) { return(ilc.MinWidth); } return(baseValue); }
/// <summary> /// Called to implement sorting functionality. /// </summary> /// <param name="sender">Typically a GridViewColumnHeader.</param> private void HeaderActionProcess(object sender) { GridViewColumnHeader header = (GridViewColumnHeader)sender; InnerListColumn column = (InnerListColumn)header.Column; UIPropertyGroupDescription dataDescription = column.DataDescription; if (dataDescription == null) { return; } // If the sorted column is sorted again, reverse the sort \\ if (Object.ReferenceEquals(column, this.sortedColumn)) { dataDescription.ReverseSortDirection(); } this.ApplySort(column, true); }
/// <summary> /// Add button was clicked. /// </summary> /// <param name="sender">Add button.</param> /// <param name="e">The RoutedEventArgs.</param> internal void AddButtonClick(object sender, RoutedEventArgs e) { InnerListColumn column = (InnerListColumn)this.PART_NotSelectedList.SelectedItem; Debug.Assert(column != null, "not null"); this.SelectedColumns.Add(column); this.NotSelectedColumns.Remove(column); // The next item in the NotSelected list // is automatically selected. // select new item in Selected list this.PART_SelectedList.SelectedItem = column; // Just to make sure, we call OnSelectionChanged // explicitly here as well. this.OnSelectionChanged(); }
/// <summary> /// Clears the sort order from the list. /// </summary> public void ClearSort() { if (null == this.CollectionView) { return; } using (this.CollectionView.DeferRefresh()) { this.sortedColumn = null; ListCollectionView lcv = (ListCollectionView)this.CollectionView; lcv.CustomSort = null; } // If columns are shown, update them to show none are sorted \\ if (this.InnerGrid != null) { this.UpdatePrimarySortColumn(); } }
private static double GetColumnWidth(InnerListColumn ilc) { return(ilc.Visible ? ilc.ActualWidth : ilc.Width); }
private static void SetColumnIsInUse(InnerListColumn ilc, bool isInUse) { ilc.Visible = isInUse; }
private static void SetColumnSortDirection(InnerListColumn ilc, ListSortDirection sortDirection) { ilc.DataDescription.SortDirection = sortDirection; }
/// <summary> /// Adds the specified column. /// Default filter rules for the column will be added if the filter is shown. /// A default search rule will be added if the search box is shown and the column's data type is searchable. /// </summary> /// <param name="column">The column to add.</param> /// <exception cref="ArgumentNullException">The specified value is a null reference.</exception> public void AddColumn(InnerListColumn column) { if (column == null) { throw new ArgumentNullException("column"); } this.AddColumn(column, this.IsFilterShown); }
static private void MinWidthProperty_PropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { InnerListColumn obj = (InnerListColumn)o; obj.OnMinWidthChanged(new PropertyChangedEventArgs <double>((double)e.OldValue, (double)e.NewValue)); }
/// <summary> /// Adds the specified columns, and optionally default filter and search rules. /// </summary> /// <param name="column">The column to add.</param> /// <param name="addDefaultFilterRules">Whether to add default filter rules for the specified column.</param> /// <exception cref="ArgumentNullException">The specified value is a null reference.</exception> public void AddColumn(InnerListColumn column, bool addDefaultFilterRules) { if (column == null) { throw new ArgumentNullException("column"); } this.List.Columns.Add(column); if (addDefaultFilterRules) { Type genericSelectorRuleType = typeof(PropertyValueSelectorFilterRule<>).MakeGenericType(column.DataDescription.DataType); ConstructorInfo selectorRuleConstructorInfo = genericSelectorRuleType.GetConstructor(new Type[] { typeof(string), typeof(string) }); SelectorFilterRule selectorRule = (SelectorFilterRule)selectorRuleConstructorInfo.Invoke(new object[] { column.DataDescription.PropertyName, column.DataDescription.DisplayName }); if (addDefaultFilterRules) { this.AddFilterRulePicker.ColumnFilterRules.Add(new AddFilterRulePickerItem(new FilterRulePanelItem(selectorRule, selectorRule.DisplayName))); } // Automatically add a search rule if the search box is shown \\ if (this.IsSearchShown) { this.SearchBox.Parser.TryAddSearchableRule<TextContainsFilterRule>(selectorRule); // Add this property to the full-text search properties \\ this.defaultFullTextSearchRule.PropertyNames.Add(column.DataDescription.PropertyName); } } }
static private void DataDescriptionProperty_PropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { InnerListColumn obj = (InnerListColumn)o; obj.OnDataDescriptionChanged(new PropertyChangedEventArgs <UIPropertyGroupDescription>((UIPropertyGroupDescription)e.OldValue, (UIPropertyGroupDescription)e.NewValue)); }
private void AddColumns(string[] propertyNames, string[] displayNames, Type[] types) { // Wait for the gridViewWindow thread to signal that loading of Window is done if (this.gridViewWindowLoaded != null) { this.gridViewWindowLoaded.WaitOne(); this.gridViewWindowLoaded = null; } this.managementList.Dispatcher.Invoke( System.Windows.Threading.DispatcherPriority.Normal, new Action( delegate() { // Pick the length of the shortest incoming arrays. Normally all incoming arrays should be of the same length. int length = propertyNames.Length; if (length > displayNames.Length) { length = displayNames.Length; } if (length > types.Length) { length = types.Length; } try { // Clear all columns in case the view is changed. this.managementList.List.Columns.Clear(); // Clear column filter rules. this.managementList.AddFilterRulePicker.ColumnFilterRules.Clear(); // Add columns with provided names and Types. for (int i = 0; i < propertyNames.Length; ++i) { DataTemplate dataTemplate; bool haveTemplate = this.managementList.FilterRulePanel.TryGetContentTemplate(types[i], out dataTemplate); InnerListColumn column = null; if(haveTemplate) { column = new InnerListColumn(new UIPropertyGroupDescription(propertyNames[i], displayNames[i], types[i])); } else { column = new InnerListColumn(new UIPropertyGroupDescription(propertyNames[i], displayNames[i], typeof(string))); } this.managementList.AddColumn(column); } this.managementList.List.SetColumnHeaderActions(); if(this.managementList.List.ItemsSource == null) { // Setting ItemsSource implicitly regenerates all columns. this.managementList.List.ItemsSource = this.listItems; } // Set focus on ListView this.managementList.List.SelectedIndex = 0; this.managementList.List.Focus(); } catch (Exception e) { // Store the exception in a local variable that will be checked later. if(e.InnerException != null) { this.exception = e.InnerException; } else { this.exception = e; } } })); }
private void AddColumns(string[] propertyNames, string[] displayNames, Type[] types) { // Wait for the gridViewWindow thread to signal that loading of Window is done if (this.gridViewWindowLoaded != null) { this.gridViewWindowLoaded.WaitOne(); this.gridViewWindowLoaded = null; } this.managementList.Dispatcher.Invoke( System.Windows.Threading.DispatcherPriority.Normal, new Action( delegate() { // Pick the length of the shortest incoming arrays. Normally all incoming arrays should be of the same length. int length = propertyNames.Length; if (length > displayNames.Length) { length = displayNames.Length; } if (length > types.Length) { length = types.Length; } try { // Clear all columns in case the view is changed. this.managementList.List.Columns.Clear(); // Clear column filter rules. this.managementList.AddFilterRulePicker.ColumnFilterRules.Clear(); // Add columns with provided names and Types. for (int i = 0; i < propertyNames.Length; ++i) { DataTemplate dataTemplate; bool haveTemplate = this.managementList.FilterRulePanel.TryGetContentTemplate(types[i], out dataTemplate); InnerListColumn column = null; if (haveTemplate) { column = new InnerListColumn(new UIPropertyGroupDescription(propertyNames[i], displayNames[i], types[i])); } else { column = new InnerListColumn(new UIPropertyGroupDescription(propertyNames[i], displayNames[i], typeof(string))); } this.managementList.AddColumn(column); } this.managementList.List.SetColumnHeaderActions(); if (this.managementList.List.ItemsSource == null) { // Setting ItemsSource implicitly regenerates all columns. this.managementList.List.ItemsSource = this.listItems; } // Set focus on ListView this.managementList.List.SelectedIndex = 0; this.managementList.List.Focus(); } catch (Exception e) { // Store the exception in a local variable that will be checked later. if (e.InnerException != null) { this.exception = e.InnerException; } else { this.exception = e; } } })); }
/// <summary> /// Clears the sort order from the list. /// </summary> public void ClearSort() { if (null == this.CollectionView) { return; } using (this.CollectionView.DeferRefresh()) { this.sortedColumn = null; ListCollectionView lcv = (ListCollectionView)this.CollectionView; lcv.CustomSort = null; } // If columns are shown, update them to show none are sorted \\ if (this.InnerGrid != null) { this.UpdatePrimarySortColumn(); } }
/// <summary> /// Sorts the list by the specified column. This has no effect if the list does not have a data source. /// </summary> /// <param name="column"> /// The column to sort /// </param> /// <param name="shouldScrollIntoView"> /// Indicates whether the SelectedItem should be scrolled into view. /// </param> /// <exception cref="ArgumentNullException">The specified value is a null reference.</exception> public void ApplySort(InnerListColumn column, bool shouldScrollIntoView) { if (column == null) { throw new ArgumentNullException("column"); } // NOTE : By setting the column here, it will be used // later to set the sorted column when the UI state // is ready. this.sortedColumn = column; // If the list hasn't been populated, don't do anything \\ if (this.CollectionView == null) { return; } this.UpdatePrimarySortColumn(); using (this.CollectionView.DeferRefresh()) { ListCollectionView lcv = (ListCollectionView)this.CollectionView; lcv.CustomSort = new PropertyValueComparer(this.GetDescriptionsForSorting(), true, FilterRuleCustomizationFactory.FactoryInstance.PropertyValueGetter); } if (shouldScrollIntoView && this.SelectedIndex > 0) { this.ScrollIntoView(this.SelectedItem); } }
/// <summary> /// Called when the ItemsSource changes to auto populate the GridView columns /// with reflection information on the first element of the ItemsSource. /// </summary> /// <param name="newValue"> /// The new ItemsSource. /// This is used just to fetch .the first collection element. /// </param> internal void PopulateColumns(System.Collections.IEnumerable newValue) { if (newValue == null) { return; // No elements, so we can't populate } IEnumerator newValueEnumerator = newValue.GetEnumerator(); if (!newValueEnumerator.MoveNext()) { return; // No first element, so we can't populate } object first = newValueEnumerator.Current; if (first == null) { return; } Debug.Assert(this.AvailableColumns.Count == 0, "AvailabeColumns should be empty at this point"); PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(first); foreach (PropertyDescriptor property in properties) { UIPropertyGroupDescription dataDescription = new UIPropertyGroupDescription(property.Name, property.Name, property.PropertyType); InnerListColumn column = new InnerListColumn(dataDescription); this.AvailableColumns.Add(column); } }
static private void VisibleProperty_PropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { InnerListColumn obj = (InnerListColumn)o; obj.OnVisibleChanged(new PropertyChangedEventArgs <bool>((bool)e.OldValue, (bool)e.NewValue)); }