【问题标题】:Expand Wpf Treeview to support Sorting扩展 Wpf Treeview 以支持排序
【发布时间】:2023-03-10 09:25:02
【问题描述】:

您好,我创建了这个小示例,我想扩展它以支持排序。

public class Country
{
    public string Name { get; set; }
    public int SortOrder { get; set; }
}

我的xml:

<TreeView Name="CountryTreeView" ItemsSource="{Binding}">
  <TreeView.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding Path=Name}"/>
    </DataTemplate>
  </TreeView.ItemTemplate>
</TreeView>

还有代码隐藏:

readonly ObservableCollection<Country> Countries;

public MainWindow()
{
   InitializeComponent();

   Countries = new ObservableCollection<Country>
   {
       new Country{Name = "Denmark", SortOrder = 0},
       new Country{Name = "Norway", SortOrder = 1},
       new Country{Name = "Sweden", SortOrder = 2},
       new Country{Name = "Iceland", SortOrder = 3},
       new Country{Name = "Greenland", SortOrder = 4},
   };

   CountryTreeView.DataContext = Countries;
}

我想让Treeview 能够根据SortOrder 的值对Countries 进行排序。

它需要能够即时执行此操作。 因此,例如,如果我将 SortOrder = 10 更改为 Name = "Denmark",TreeView 将自动反映这一点。

【问题讨论】:

    标签: c# wpf c#-4.0 treeview


    【解决方案1】:

    我认为 TreeViews 没有默认排序。您可以在将项目输入集合之前对其进行排序,也可以覆盖 ObservableCollection 以包含 Sort 方法。

    我在我的一个项目中覆盖它:

    public class SortableObservableCollection<T> : ObservableCollection<T>
    {
        // Constructors
        public SortableObservableCollection() : base(){}
        public SortableObservableCollection(List<T> l) : base(l){}
        public SortableObservableCollection(IEnumerable<T> l) :base (l) {}
    
        #region Sorting
    
        /// <summary>
        /// Sorts the items of the collection in ascending order according to a key.
        /// </summary>
        /// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
        /// <param name="keySelector">A function to extract a key from an item.</param>
        public void Sort<TKey>(Func<T, TKey> keySelector)
        {
            InternalSort(Items.OrderBy(keySelector));
        }
    
        /// <summary>
        /// Sorts the items of the collection in descending order according to a key.
        /// </summary>
        /// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
        /// <param name="keySelector">A function to extract a key from an item.</param>
        public void SortDescending<TKey>(Func<T, TKey> keySelector)
        {
            InternalSort(Items.OrderByDescending(keySelector));
        }
    
        /// <summary>
        /// Sorts the items of the collection in ascending order according to a key.
        /// </summary>
        /// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
        /// <param name="keySelector">A function to extract a key from an item.</param>
        /// <param name="comparer">An <see cref="IComparer{T}"/> to compare keys.</param>
        public void Sort<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
        {
            InternalSort(Items.OrderBy(keySelector, comparer));
        }
    
        /// <summary>
        /// Moves the items of the collection so that their orders are the same as those of the items provided.
        /// </summary>
        /// <param name="sortedItems">An <see cref="IEnumerable{T}"/> to provide item orders.</param>
        private void InternalSort(IEnumerable<T> sortedItems)
        {
            var sortedItemsList = sortedItems.ToList();
    
            foreach (var item in sortedItemsList)
            {
                Move(IndexOf(item), sortedItemsList.IndexOf(item));
            }
        }
    
        #endregion // Sorting
    }
    

    然后,您可以通过调用类似

    的方法对其进行排序
    Countries.Sort(country => country.SortOrder);
    

    我喜欢覆盖它,因为它还可以让我添加额外的功能,例如 IndexOfAddRange/RemoveRange

    【讨论】:

      【解决方案2】:

      您还可以使用CollectionViewSource.GetDefaultViewListCollectionView 为您进行排序,但您也必须为所有子集合设置它。我使用 linq 查询来展平我的列表以查找所有子项并设置排序。

      foreach (var structure in Model.Structures.Flatten(t => t.SubItems))
      {
          var view = CollectionViewSource
              .GetDefaultView(structure.SubItems) as ListCollectionView;
      
          if (view != null)
          {
              view.CustomSort = (x,y) => string.Compare( x, y );
          }
      }
      

      其他地方

      public static IEnumerable<T> Flatten<T>(
          this IEnumerable<T> list, Func<T, IEnumerable<T>> subitems)
      {
          foreach (T child in list)
          {
              yield return child;
      
              foreach (T other in Flatten(subitems(child), subitems))
              {
                  yield return other;
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        我开发了一个视图模型库,它可以做很多事情,包括让您按排序顺序显示分层数据。该库在this article 中进行了描述。该文章不包含排序示例,但您可以轻松修改 Demo 2 的 View Model 以对其分层数据进行排序。只需执行以下操作:

        1. 传递给SampleTreeNodePM 的基本构造函数的三个布尔参数中的第一个指示视图模型集合是否应使用与域模型集合相同的索引。将此值更改为 false
        2. DesiredPosition 方法覆盖的返回值的最后一个参数是一个布尔值,指示是否对视图模型集合进行排序。将此值更改为true
        3. 继上一步之后,您现在需要修改域模型对象SampleTreeNode,以实现IComparable&lt;SampleTreeNode&gt;CompareTo 方法只需将作业委托给 Name 字符串属性:

          public int CompareTo( SampleTreeNode other )
          {
              return Name.CompareTo( other.Name );
          }
          

        关于如您的问题所说的“即时”更新位置,只需在进行更改后调用我的库的 HierarchicalPresentationModel.UpdatePosition 方法即可。

        【讨论】:

          猜你喜欢
          • 2023-03-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-07-22
          • 1970-01-01
          • 1970-01-01
          • 2012-06-13
          • 1970-01-01
          相关资源
          最近更新 更多