Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
Innerlist.cs713 linesDownload Raw Back to ManagementList
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections;6using System.Collections.Generic;7using System.Collections.ObjectModel;8using System.Collections.Specialized;9using System.ComponentModel;10using System.Diagnostics;11using System.Globalization;12using System.Text;13using System.Windows;14using System.Windows.Automation;15using System.Windows.Controls;16using System.Windows.Controls.Primitives;17using System.Windows.Data;18using System.Windows.Documents;19using System.Windows.Input;20using System.Windows.Markup;21using System.Windows.Media;22using System.Windows.Media.Imaging;23using System.Windows.Shapes;24using System.Windows.Threading;25 26namespace Microsoft.Management.UI.Internal27{28    /// <content>29    /// Partial class implementation for InnerList control.30    /// </content>31    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]32    public partial class InnerList : System.Windows.Controls.ListView33    {34        #region internal fields35        #region StyleCop Suppression - generated code36        /// <summary>37        /// The current ICollectionView being displayed.38        /// </summary>39        internal ICollectionView CollectionView;40 41        #endregion StyleCop Suppression - generated code42        #endregion internal fields43 44        #region private fields45        /// <summary>46        /// The current GridView.47        /// </summary>48        private InnerListGridView innerGrid;49 50        private InnerListColumn sortedColumn;51 52        /// <summary>53        /// ContextMenu for InnerList columns.54        /// </summary>55        private ContextMenu contextMenu;56 57        /// <summary>58        /// Private setter for <see cref="Columns"/>.59        /// </summary>60        private ObservableCollection<InnerListColumn> columns = new ObservableCollection<InnerListColumn>();61 62        /// <summary>63        /// Gets or sets whether the current items source is non-null and has items.64        /// </summary>65        private bool itemsSourceIsEmpty = false;66 67        #endregion private fields68 69        #region constructors70 71        /// <summary>72        /// Initializes a new instance of this control.73        /// </summary>74        public InnerList()75            : base()76        {77            // This flag is needed to dramatically increase performance of scrolling \\78            VirtualizingStackPanel.SetVirtualizationMode(this, VirtualizationMode.Recycling);79 80            AutomationProperties.SetAutomationId(this, "InnerList"); // No localization needed81        }82        #endregion constructors83 84        #region Events85 86        /// <summary>87        ///  Register PropertyChangedEventHandler ItemSourcesPropertyChanged .88        /// </summary>89        public event PropertyChangedEventHandler ItemSourcesPropertyChanged;90        #endregion Events91 92        #region public properties93 94        /// <summary>95        /// Gets ItemsSource instead.96        /// <see cref="InnerList"/> Does not support adding to Items.97        /// </summary>98        [Browsable(false)]99        public new ItemCollection Items100        {101            get102            {103                return base.Items;104            }105        }106 107        /// <summary>108        /// Gets the column that is sorted, or <c>null</c> if no column is sorted.109        /// </summary>110        public InnerListColumn SortedColumn111        {112            get113            {114                return this.sortedColumn;115            }116        }117 118        /// <summary>119        /// Gets InnerListGridView.120        /// </summary>121        public InnerListGridView InnerGrid122        {123            get { return this.innerGrid; }124            protected set { this.innerGrid = value; }125        }126 127        /// <summary>128        /// Gets the collection of columns that this list should display.129        /// </summary>130        public ObservableCollection<InnerListColumn> Columns131        {132            get { return this.columns; }133        }134 135        #endregion public properties136 137        #region public methods138 139        /// <summary>140        /// Causes the object to scroll into view.141        /// </summary>142        /// <param name="item">Object to scroll.</param>143        /// <remarks>This method overrides ListBox.ScrollIntoView(), which throws NullReferenceException when VirtualizationMode is set to Recycling.144        /// This implementation uses a workaround recommended by the WPF team.</remarks>145        public new void ScrollIntoView(object item)146        {147            Dispatcher.BeginInvoke(148                DispatcherPriority.Background,149                (DispatcherOperationCallback)((arg) =>150                {151                    if (this.IsLoaded)152                    {153                        base.ScrollIntoView(arg);154                    }155 156                    return null;157                }),158                item);159        }160 161        /// <summary>162        /// Causes the object to scroll into view from the top, so that it tends to appear at the bottom of the scroll area.163        /// </summary>164        /// <param name="item">Object to scroll.</param>165        public void ScrollIntoViewFromTop(object item)166        {167            if (this.Items.Count > 0)168            {169                this.ScrollIntoView(this.Items[0]);170                this.ScrollIntoView(item);171            }172        }173 174        /// <summary>175        /// Updates the InnerGrid based upon the columns collection.176        /// </summary>177        public void RefreshColumns()178        {179            this.UpdateView(this.ItemsSource);180        }181 182        /// <summary>183        /// Sorts the list by the specified column. This has no effect if the list does not have a data source.184        /// </summary>185        /// <param name="column">186        /// The column to sort187        /// </param>188        /// <param name="shouldScrollIntoView">189        /// Indicates whether the SelectedItem should be scrolled into view.190        /// </param>191        /// <exception cref="ArgumentNullException">The specified value is a null reference.</exception>192        public void ApplySort(InnerListColumn column, bool shouldScrollIntoView)193        {194            ArgumentNullException.ThrowIfNull(column);195 196            // NOTE : By setting the column here, it will be used197            // later to set the sorted column when the UI state198            // is ready.199            this.sortedColumn = column;200 201            // If the list hasn't been populated, don't do anything \\202            if (this.CollectionView == null)203            {204                return;205            }206 207            this.UpdatePrimarySortColumn();208 209            using (this.CollectionView.DeferRefresh())210            {211                ListCollectionView lcv = (ListCollectionView)this.CollectionView;212                lcv.CustomSort = new PropertyValueComparer(this.GetDescriptionsForSorting(), true, FilterRuleCustomizationFactory.FactoryInstance.PropertyValueGetter);213            }214 215            if (shouldScrollIntoView && this.SelectedIndex > 0)216            {217                this.ScrollIntoView(this.SelectedItem);218            }219        }220 221        private void UpdatePrimarySortColumn()222        {223            foreach (InnerListColumn column in this.InnerGrid.AvailableColumns)224            {225                bool isPrimarySortColumn = object.ReferenceEquals(this.sortedColumn, column);226 227                InnerList.SetIsPrimarySortColumn(column, isPrimarySortColumn);228                InnerList.SetIsPrimarySortColumn((GridViewColumnHeader)column.Header, isPrimarySortColumn);229            }230        }231 232        /// <summary>233        /// Gets a list of data descriptions for the columns that are not the primary sort column.234        /// </summary>235        /// <returns>A list of data descriptions for the columns that are not the primary sort column.</returns>236        private List<UIPropertyGroupDescription> GetDescriptionsForSorting()237        {238            List<UIPropertyGroupDescription> dataDescriptions = new List<UIPropertyGroupDescription>();239 240            dataDescriptions.Add(this.SortedColumn.DataDescription);241 242            foreach (InnerListColumn column in this.InnerGrid.Columns)243            {244                if (!object.ReferenceEquals(this.SortedColumn, column))245                {246                    dataDescriptions.Add(column.DataDescription);247                }248            }249 250            return dataDescriptions;251        }252 253        /// <summary>254        /// Clears the sort order from the list.255        /// </summary>256        public void ClearSort()257        {258            if (this.CollectionView == null)259            {260                return;261            }262 263            using (this.CollectionView.DeferRefresh())264            {265                this.sortedColumn = null;266                ListCollectionView lcv = (ListCollectionView)this.CollectionView;267                lcv.CustomSort = null;268            }269 270            // If columns are shown, update them to show none are sorted \\271            if (this.InnerGrid != null)272            {273                this.UpdatePrimarySortColumn();274            }275        }276 277        #endregion public methods278 279        #region internal methods280 281        #endregion internal methods282 283        #region protected methods284        /// <summary>285        /// Called when the ItemsSource changes to set internal fields, subscribe to the view change286        /// and possibly autopopulate columns.287        /// </summary>288        /// <param name="oldValue">Previous ItemsSource.</param>289        /// <param name="newValue">Current ItemsSource.</param>290        protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)291        {292            base.OnItemsSourceChanged(oldValue, newValue);293 294            this.itemsSourceIsEmpty = this.ItemsSource != null && this.ItemsSource.GetEnumerator().MoveNext() == false;295 296            // A view can be created if there is data to auto-generate columns, or columns are added programmatically \\297            bool canCreateView = (this.ItemsSource != null) &&298                (this.itemsSourceIsEmpty == false || this.AutoGenerateColumns == false);299 300            if (canCreateView)301            {302                this.UpdateViewAndCollectionView(this.ItemsSource);303 304                // If there are items, select the first item now \\305                this.SelectedIndex = this.itemsSourceIsEmpty ? -1 : 0;306            }307            else308            {309                // Release the current inner grid \\310                this.ReleaseInnerGridReferences();311 312                // clean up old state if can not set the state.313                this.SetCollectionView(null);314                this.innerGrid = null;315                this.View = null;316            }317        }318 319        /// <summary>320        /// Called when ItemsChange to throw an exception indicating we don't support321        /// changing Items directly.322        /// </summary>323        /// <param name="e">Event parameters.</param>324        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)325        {326            base.OnItemsChanged(e);327 328            if (e.NewItems != null)329            {330                // If the items source now has items, select the first item \\331                if (this.itemsSourceIsEmpty && this.Items.Count > 0)332                {333                    this.SelectedIndex = 0;334                    this.itemsSourceIsEmpty = false;335                }336 337                if (e.Action == NotifyCollectionChangedAction.Add)338                {339                    if (this.InnerGrid == null)340                    {341                        this.UpdateViewAndCollectionView(this.ItemsSource);342                    }343                }344            }345        }346 347        /// <summary>348        /// Called when a key is pressed while within the InnerList scope.349        /// </summary>350        /// <param name="e">The event args.</param>351        protected override void OnKeyDown(KeyEventArgs e)352        {353            base.OnKeyDown(e);354 355            if ((e.Key == Key.Left || e.Key == Key.Right) &&356                Keyboard.Modifiers == ModifierKeys.None)357            {358                // If pressing Left or Right on a column header, move the focus \\359                GridViewColumnHeader header = e.OriginalSource as GridViewColumnHeader;360 361                if (header != null)362                {363                    header.MoveFocus(new TraversalRequest(KeyboardHelp.GetNavigationDirection(this, e.Key)));364                    e.Handled = true;365                }366            }367        }368 369        #endregion protected methods370 371        #region static private methods372 373        /// <summary>374        /// Called when the View property is changed.375        /// </summary>376        /// <param name="obj">InnerList whose property is being changed.</param>377        /// <param name="e">Event arguments.</param>378        private static void InnerList_OnViewChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)379        {380            InnerList thisList = (InnerList)obj;381            GridView newGrid = e.NewValue as GridView;382            InnerListGridView innerGrid = e.NewValue as InnerListGridView;383            if (newGrid != null && innerGrid == null)384            {385                throw new NotSupportedException(string.Format(386                    CultureInfo.InvariantCulture,387                   InvariantResources.ViewSetWithType,388                   nameof(GridView),389                   nameof(InnerListGridView)));390            }391 392            ((InnerList)obj).innerGrid = innerGrid;393        }394 395        /// <summary>396        /// Gets the exception to be thrown when using Items.397        /// </summary>398        /// <returns>The exception to be thrown when using Items.</returns>399        private static NotSupportedException GetItemsException()400        {401            return new NotSupportedException(402                string.Format(403                    CultureInfo.InvariantCulture,404                    InvariantResources.NotSupportAddingToItems,405                    nameof(InnerList),406                    ItemsControl.ItemsSourceProperty.Name));407        }408        #endregion static private methods409 410        #region instance private methods411        /// <summary>412        /// Called from OnItemsSourceChanged to set the collectionView field and413        /// subscribe to the collectionView changed event.414        /// </summary>415        /// <param name="newValue">ITemsSource passed to OnItemsSourceChanged.</param>416        private void SetCollectionView(System.Collections.IEnumerable newValue)417        {418            if (newValue == null)419            {420                this.CollectionView = null;421            }422            else423            {424                CollectionViewSource newValueViewSource = newValue as CollectionViewSource;425                if (newValueViewSource != null && newValueViewSource.View != null)426                {427                    this.CollectionView = newValueViewSource.View;428                }429                else430                {431                    this.CollectionView = CollectionViewSource.GetDefaultView(newValue);432                }433            }434        }435 436        /// <summary>437        /// Update View And CollectionView.438        /// </summary>439        /// <param name="value">InnerList object.</param>440        private void UpdateViewAndCollectionView(IEnumerable value)441        {442            Debug.Assert(value != null, "value should be non-null");443 444            // SetCollectionView deals with a null newEnumerable445            this.SetCollectionView(value);446 447            this.UpdateView(value);448 449            // Generate property changed event.450            if (this.ItemSourcesPropertyChanged != null)451            {452                this.ItemSourcesPropertyChanged(this, new PropertyChangedEventArgs("ItemsSource"));453            }454        }455 456        private void UpdateView(IEnumerable value)457        {458            // NOTE : We need to clear the SortDescription before459            // clearing the InnerGrid.Columns so that the Adorners460            // are appropriately cleared.461            InnerListColumn sortedColumn = this.SortedColumn;462            this.ClearSort();463 464            // Release the current inner grid \\465            this.ReleaseInnerGridReferences();466 467            if (this.AutoGenerateColumns)468            {469                this.innerGrid = new InnerListGridView();470 471                // PopulateColumns deals with a null newEnumerable472                this.innerGrid.PopulateColumns(value);473            }474            else475            {476                this.innerGrid = new InnerListGridView(this.Columns);477            }478 479            this.View = this.innerGrid;480            this.SetColumnHeaderActions();481 482            if (sortedColumn != null && this.Columns.Contains(sortedColumn))483            {484                this.ApplySort(sortedColumn, false);485            }486        }487 488        /// <summary>489        /// Releases all references to the current inner grid, if one exists.490        /// </summary>491        private void ReleaseInnerGridReferences()492        {493            if (this.innerGrid != null)494            {495                // Tell the inner grid to release its references \\496                this.innerGrid.ReleaseReferences();497 498                // Release the column headers \\499                foreach (InnerListColumn column in this.innerGrid.AvailableColumns)500                {501                    GridViewColumnHeader header = column.Header as GridViewColumnHeader;502 503                    if (header != null)504                    {505                        header.Click -= this.Header_Click;506                        header.PreviewKeyDown -= this.Header_KeyDown;507                    }508                }509            }510        }511 512        /// <summary>513        /// Called when the ItemsSource changes, after SetGridview to add event handlers514        /// to the column header.515        /// </summary>516        internal void SetColumnHeaderActions()517        {518            if (this.innerGrid == null)519            {520                return;521            }522 523            // set context menu524            this.innerGrid.ColumnHeaderContextMenu = this.GetListColumnsContextMenu();525 526            foreach (GridViewColumn column in this.innerGrid.AvailableColumns)527            {528                // A string header needs an explicit GridViewColumnHeader529                // so we can hook up our events530                string headerString = column.Header as string;531                if (headerString != null)532                {533                    GridViewColumnHeader columnHeader = new GridViewColumnHeader();534                    columnHeader.Content = headerString;535                    column.Header = columnHeader;536                }537 538                GridViewColumnHeader header = column.Header as GridViewColumnHeader;539 540                if (header != null)541                {542                    // header Click543                    header.Click += this.Header_Click;544                    header.PreviewKeyDown += this.Header_KeyDown;545                }546 547                // If it is a GridViewColumnHeader we will not have the same nice sorting and grouping548                // capabilities549            }550        }551 552        #region ApplicationCommands.Copy553 554        partial void OnCopyCanExecuteImplementation(CanExecuteRoutedEventArgs e)555        {556            e.CanExecute = this.SelectedItems.Count > 0;557        }558 559        partial void OnCopyExecutedImplementation(ExecutedRoutedEventArgs e)560        {561            string text = this.GetClipboardTextForSelectedItems();562            this.SetClipboardWithSelectedItemsText(text);563        }564 565        #region Copy Helpers566 567        /// <summary>568        /// Gets a tab-delimited string representing the data of the selected rows.569        /// </summary>570        /// <returns>A tab-delimited string representing the data of the selected rows.</returns>571        protected internal string GetClipboardTextForSelectedItems()572        {573            StringBuilder text = new StringBuilder();574 575            foreach (object value in this.Items)576            {577                if (this.SelectedItems.Contains(value))578                {579                    string entry = this.GetClipboardTextLineForSelectedItem(value);580                    text.AppendLine(entry);581                }582            }583 584            return text.ToString();585        }586 587        private string GetClipboardTextLineForSelectedItem(object value)588        {589            StringBuilder entryText = new StringBuilder();590 591            foreach (InnerListColumn column in this.InnerGrid.Columns)592            {593                object propertyValue;594                if (!FilterRuleCustomizationFactory.FactoryInstance.PropertyValueGetter.TryGetPropertyValue(column.DataDescription.PropertyName, value, out propertyValue))595                {596                    propertyValue = string.Empty;597                }598 599                entryText.Append(CultureInfo.CurrentCulture, $"{propertyValue}\t");600            }601 602            return entryText.ToString();603        }604 605        private void SetClipboardWithSelectedItemsText(string text)606        {607            if (string.IsNullOrEmpty(text))608            {609                return;610            }611 612            DataObject data = new DataObject(DataFormats.UnicodeText, text);613            Clipboard.SetDataObject(data);614        }615 616        #endregion Copy Helpers617 618        #endregion ApplicationCommands.Copy619 620        /// <summary>621        /// Called to implement sorting functionality on column header pressed by space or enter key.622        /// </summary>623        /// <param name="sender">Typically a GridViewColumnHeader.</param>624        /// <param name="e">The event information.</param>625        private void Header_KeyDown(object sender, KeyEventArgs e)626        {627            if (e.Key != Key.Space && e.Key != Key.Enter)628            {629                return;630            }631 632            // Call HeaderActionProcess when space or enter key pressed633            this.HeaderActionProcess(sender);634            e.Handled = true;635        }636 637        /// <summary>638        /// Called to implement sorting functionality on column header click.639        /// </summary>640        /// <param name="sender">Typically a GridViewColumnHeader.</param>641        /// <param name="e">The event information.</param>642        private void Header_Click(object sender, RoutedEventArgs e)643        {644            // Call HeaderActionProcess when mouse clicked on the header645            this.HeaderActionProcess(sender);646        }647 648        /// <summary>649        /// Called to implement sorting functionality.650        /// </summary>651        /// <param name="sender">Typically a GridViewColumnHeader.</param>652        private void HeaderActionProcess(object sender)653        {654            GridViewColumnHeader header = (GridViewColumnHeader)sender;655            InnerListColumn column = (InnerListColumn)header.Column;656            UIPropertyGroupDescription dataDescription = column.DataDescription;657 658            if (dataDescription == null)659            {660                return;661            }662 663            // If the sorted column is sorted again, reverse the sort \\664            if (object.ReferenceEquals(column, this.sortedColumn))665            {666                dataDescription.ReverseSortDirection();667            }668 669            this.ApplySort(column, true);670        }671 672        /// <summary>673        /// Create default Context Menu.674        /// </summary>675        /// <returns>ContextMenu of List Columns.</returns>676        private ContextMenu GetListColumnsContextMenu()677        {678            this.contextMenu = new ContextMenu();679 680            // Add Context Menu item.681            this.SetColumnPickerContextMenuItem();682 683            return this.contextMenu;684        }685 686        /// <summary>687        /// Set up context menu item for Column Picker feature.688        /// </summary>689        /// <returns>True if it is successfully set up.</returns>690        private bool SetColumnPickerContextMenuItem()691        {692            MenuItem columnPicker = new MenuItem();693            AutomationProperties.SetAutomationId(columnPicker, "ChooseColumns");694            columnPicker.Header = UICultureResources.ColumnPicker;695            columnPicker.Click += this.innerGrid.OnColumnPicker;696 697            this.contextMenu.Items.Add(columnPicker);698 699            return true;700        }701 702        static partial void StaticConstructorImplementation()703        {704            // Adds notification for the View changing705            ListView.ViewProperty.OverrideMetadata(706                typeof(InnerList),707                new PropertyMetadata(new PropertyChangedCallback(InnerList_OnViewChanged)));708        }709 710        #endregion instance private methods711    }712}713