扩展 Wpf Treeview 以支持排序

发布于 2024-10-29 07:31:11 字数 1186 浏览 2 评论 0原文

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

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

我的 xaml:

<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 进行排序。

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

Hi I created this small example, and I would like to expand it to support Sorting.

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

My xaml:

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

And the code-behind:

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;
}

I would like to make it possible for the Treeview to Sort the Countries depending on the SortOrder value.

It needs to be able to do this on the fly.
So if I for example change SortOrder = 10 for Name = "Denmark" the TreeView would automatically reflect this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

jJeQQOZ5 2024-11-05 07:31:11

我认为 TreeView 没有默认排序。您可以在将项目输入集合之前对其进行排序,也可以覆盖 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/<代码>删除范围

I don't think there is a default sort for TreeViews. You can either sort the items prior to entering them into the collection, or overwrite the ObservableCollection to include a Sort method.

I overwrite it in one of my projects:

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
}

You would then sort it by calling something like

Countries.Sort(country => country.SortOrder);

I like overwriting it because it let me add additional functionality to it as well such as IndexOf or AddRange/RemoveRange

忆依然 2024-11-05 07:31:11

您还可以将 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;
        }
    }
}

You can also use the CollectionViewSource.GetDefaultView with ListCollectionView to do the sorting for you, tho you do have to set it for all the child collections as well. I use a linq query to flatten my list to find all the children and set the sorting.

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 );
    }
}

elsewhere

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;
        }
    }
}
猫弦 2024-11-05 07:31:11

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

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

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

关于如您的问题所述“动态”更新位置,只需调用我的库的 HierarchicalPresentationModel进行更改后的.UpdatePosition 方法。

I developed a View Model library which does a number of things, including letting you display hierarchical data in sorted order. The library is described in this article. The piece doesn't include a sorting example, but you can easily modify the Demo 2's View Model to sort its hierarchical data. Just do the following:

  1. The first of three boolean arguments passed to SampleTreeNodePM's base constructor indicates if the View Model collections should use the same indices as the Domain Model collections or not. Change this value to false.
  2. The last argument to the DesiredPosition method override's return value is a boolean that indicates whether to sort the View Model collection or not. Change this value to true.
  3. Following from the previous step, you now need to modify the Domain Model object, SampleTreeNode, to implement IComparable<SampleTreeNode>. The CompareTo method need simply delegate the job to the Name string property:

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

Regarding updating the position "on the fly" as your question says, just call my library's HierarchicalPresentationModel.UpdatePosition method after making the change.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文