对C#中的TreeViewItems列表进行数字排序 [英] Numerically sort a List of TreeViewItems in C#

查看:155
本文介绍了对C#中的TreeViewItems列表进行数字排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题是对问题.目前,我的总体目标是根据header中输入的值,以数字升序将其添加到程序的TreeViewItem(我的TreeViewItem在运行时向其添加了子节点).

This question is a follow up to this question. My overall goal at the moment is to add to my program's TreeViewItem (my TreeViewItem has child nodes added to it at run-time) in numerical ascending order according to the value entered in for the header.

我使用了我并不十分熟悉的工具ModelView收到了答案,并且还告诉我可以使用TreeViewItemsList来完成.由于缺乏对ModelView的经验,我决定探索List选项.

I received an answer using a ModelView, a tool that I am not all that familiar with, and I was also told that this could be done by using a List of TreeViewItems. I have decided to explore the List option due to my lack of experience with ModelView.

在我的研究中,我了解到TreeViewItems中的Lists有点不同,因为您确实不能像array那样引用它们.这使它们更难处理.我将解释当前的方法并发布我的代码.请引导我朝正确的方向发展,并提供编码解决方案的答案.我目前无法使用treeViewListAdd函数.我已经在试图对该区域进行处理的注释中编写了伪代码.

In my research I've learned that Lists of TreeViewItems are a little different, because you really can't reference them like you can an array. This makes them more difficult to do work with. I'll explain my current method and post my code. Please steer me in the right direction and provide answers with coding solutions. I'm currently stuck on my treeViewListAdd function. I have written pseudo code in comments on what I am trying to do with that area.

*注意:我是从单独的窗口添加到我的TreeViewItem

*Note: I am adding to my TreeViewItem from a separate window

现在,我的添加TreeViewItem流程包括:

Right now my add TreeViewItem process consists of:

  1. 检查输入的项目是否为数字(完成)
  2. if不是数字,break操作(完成)
  3. else-继续添加子项(完成)
  4. 检查重复的孩子(完成)
  5. 找到
  6. if重复项break操作(完成)
  7. else-继续(完成)
  8. 创建TreeViewItemList (完成-但未实现)
  9. 为新的子节点(完成)
  10. 创建TreeViewItem
  11. TVI header是通过textBox (完成)
  12. 中的用户文本设置的
  13. 传递给尝试按数字顺序添加到List的功能(问题区域)
  14. 在主窗口(问题区域)
  15. 中将已排序的List添加到TreeViewItem
  1. Check to see if item entered is numerical (DONE)
  2. if not numerical, break operation (DONE)
  3. else -- continue with adding child item (DONE)
  4. Check for duplicate children (DONE)
  5. if duplicate is found break operation (DONE)
  6. else -- continue (DONE)
  7. Create List of TreeViewItem (DONE -- But not implemented)
  8. Create TreeViewItem for new child node (DONE)
  9. TVI header is set from user text in textBox (DONE)
  10. Pass to function that attempts to add to the List in numerical order (Problem Area)
  11. Add sorted List to TreeViewItem in main window (Problem Area)

我当前的代码:

//OKAY - Add child to TreeViewItem in Main Window
private void button2_Click(object sender, RoutedEventArgs e)
{
    //STEP 1: Checks to see if entered text is a numerical value
    string Str = textBox1.Text.Trim();
    double Num;
    bool isNum = double.TryParse(Str, out Num);

    //STEP 2: If not numerical value, warn user
    if (isNum == false)
        MessageBox.Show("Value must be Numerical");
    else //STEP 3: else, continue
    {
        //close window
        this.Close();

        //Query for Window1
        var mainWindow = Application.Current.Windows
            .Cast<Window1>()
            .FirstOrDefault(window => window is Window1) as Window1;

        //STEP 4: Check for duplicate
        //declare TreeViewItem from mainWindow
        TreeViewItem locations = mainWindow.TreeViewItem;
        //Passes to function -- checks for DUPLICATE locations
        CheckForDuplicate(locations.Items, textBox1.Text);

        //STEP 5: if Duplicate exists -- warn user
        if (isDuplicate == true)
            MessageBox.Show("Sorry, the number you entered is a duplicate of a current Node, please try again.");
        else //STEP 6: else -- create child node
        {
            //STEP 7
            List<TreeViewItem> treeViewList = new List<TreeViewItem>();

            //STEP 8: Creates child TreeViewItem for TVI in main window
            TreeViewItem newLocation = new TreeViewItem();

            //STEP 9: Sets Headers for new child nodes
            newLocation.Header = textBox1.Text;

            //STEP 10: Pass to function -- adds/sorts List in numerical ascending order
            treeViewListAdd(ref treeViewList, newLocation);

            //STEP 11: Add children to TVI in main window
            //This step will of course need to be changed to add the list
            //instead of just the child node
            mainWindow.TreeViewItem.Items.Add(newLocation);
        }
    }
}

//STEP 4: Checks to see whether the header entered is a DUPLICATE
private void CheckForDuplicate(ItemCollection treeViewItems, string input)
{
        for (int index = 0; index < treeViewItems.Count; index++)
        {
            TreeViewItem item = (TreeViewItem)treeViewItems[index];
            string header = item.Header.ToString();

            if (header == input)
            {
                isDuplicate = true;
                break;
            }
            else
                isDuplicate = false;
        }
}

//STEP 10: Adds to the TreeViewItem list in numerical ascending order
private void treeViewListAdd(ref List<TreeViewItem> currentList, TreeViewItem addLocation)
{
        //if there are no TreeViewItems in the list, add the current one
        if (currentList.Count() == 0)
            currentList.Add(addLocation);
        else
        {
            //gets the index of the last item in the List
            int lastItem = currentList.Count() - 1;

            /*
            if (value in header > lastItem)
                currentList.Add(addLocation);
            else
            {
                //iterate through list and add TreeViewItem
                //where appropriate
            }
            **/
        }
}

非常感谢您的帮助.我试图表明自己一直在努力,并尽我所能尝试一切.

Thanks a lot for the help. I tried to show that I have been working on this and trying everything that I could on my own.

根据要求,这是我的TreeView的结构.用户从第3层开始的所有内容都会动态添加...

As requested, here is the structure of my TreeView. Everything from the 3rd level and down is dynamically added by the user...

推荐答案

好.删除所有代码,然后重新开始.

Ok. Delete all your code and start all over.

1 :在WPF中编写一行代码之前,必须先阅读MVVM.

1: It is essential that you read up on MVVM before writing a single line of code in WPF.

您可以在此处此处

<Window x:Class="MiscSamples.SortedTreeView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cmp="clr-namespace:System.ComponentModel;assembly=WindowsBase"
        Title="SortedTreeView" Height="300" Width="300">
    <DockPanel>
        <TextBox Text="{Binding NewValueString}" DockPanel.Dock="Top"/>
        <Button Click="AddNewItem" DockPanel.Dock="Top" Content="Add"/>
        <TreeView ItemsSource="{Binding ItemsView}" SelectedItemChanged="OnSelectedItemChanged">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding ItemsView}">
                    <TextBlock Text="{Binding Value}"/>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </DockPanel>
</Window>

后面的代码:

public partial class SortedTreeView : Window
{
    public SortedTreeViewWindowViewModel ViewModel { get { return DataContext as SortedTreeViewWindowViewModel; } set { DataContext = value; } }

    public SortedTreeView()
    {
        InitializeComponent();
        ViewModel = new SortedTreeViewWindowViewModel()
            {
                Items = {new TreeViewModel(1)}
            };
    }

    private void AddNewItem(object sender, RoutedEventArgs e)
    {
        ViewModel.AddNewItem();
    }

    //Added due to limitation of TreeViewItem described in http://stackoverflow.com/questions/1000040/selecteditem-in-a-wpf-treeview
    private void OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        ViewModel.SelectedItem = e.NewValue as TreeViewModel;
    }
}

2::您在上面注意到的第一件事是背后的代码没有任何作用.它只是将功能委托给称为ViewModel的东西(不是ModelView,这是拼写错误)

2: First thing you can notice above is that the Code Behind does NOTHING. It just delegates functionality to something called the ViewModel (not ModelView, which is a misspelling)

那是为什么?

Why is that?

因为这是一种更好的方法.时期.将应用程序逻辑/业务逻辑和数据与用户界面进行分隔解耦是任何开发人员有史以来最好的事情.

Because it's a much better approach. Period. Having the application logic / business logic and data separated and decoupled from the UI is the best thing to ever happen to any developer.

那么,ViewModel是关于什么的?

So, What's the ViewModel about?

3: ViewModel公开包含要在视图中显示的包含 Data Properties和包含用于对Data进行操作的逻辑的Methods.

3: The ViewModel exposes Properties that contain the Data to be shown in the View, and Methods that contain the logic to operate with the Data.

所以就这么简单:

public class SortedTreeViewWindowViewModel: PropertyChangedBase
{
    private string _newValueString;
    public int? NewValue { get; set; }

    public string NewValueString
    {
        get { return _newValueString; }
        set
        {
            _newValueString = value;
            int integervalue;

            //If the text is a valid numeric value, use that to create a new node.
            if (int.TryParse(value, out integervalue))
                NewValue = integervalue;
            else
                NewValue = null;

            OnPropertyChanged("NewValueString");
        }
    }

    public TreeViewModel SelectedItem { get; set; }

    public ObservableCollection<TreeViewModel> Items { get; set; }

    public ICollectionView ItemsView { get; set; }

    public SortedTreeViewWindowViewModel()
    {
        Items = new ObservableCollection<TreeViewModel>();
        ItemsView = new ListCollectionView(Items) {SortDescriptions = { new SortDescription("Value",ListSortDirection.Ascending)}};
    }

    public void AddNewItem()
    {
        ObservableCollection<TreeViewModel> targetcollection;

        //Insert the New Node as a Root node if nothing is selected.
        targetcollection = SelectedItem == null ? Items : SelectedItem.Items;

        if (NewValue != null && !targetcollection.Any(x => x.Value == NewValue))
        {
            targetcollection.Add(new TreeViewModel(NewValue.Value));
            NewValueString = string.Empty;    
        }

    }
}

看到了吗? AddNewItem()方法中的5行代码可以满足您的所有11个要求.没有Header.ToString()东西,没有铸造任何东西,没有背后的可怕代码.

See? All your 11 requirements are fulfilled by 5 lines of code in the AddNewItem() method. No Header.ToString() stuff, no casting anything, no horrible code behind approaches.

简单,简单的属性和INotifyPropertyChanged.

那排序呢?

And what about the sorting?

4 :排序是由CollectionView执行的,它发生在ViewModel级别,而不是View级别.

4: The sorting is performed by the CollectionView, and it occurs at the ViewModel level, not at the View Level.

为什么?

因为数据与用户界面中的视觉表示是分开的.

Because Data is kept separate from it's visual representation in the UI.

5:最后,这是实际的数据项:

5: Finally, here is the actual Data Item:

public class TreeViewModel: PropertyChangedBase
{
    public int Value { get; set; }

    public ObservableCollection<TreeViewModel> Items { get; set; }

    public CollectionView ItemsView { get; set; }

    public TreeViewModel(int value)
    {
        Items = new ObservableCollection<TreeViewModel>();
        ItemsView = new ListCollectionView(Items)
            {
                SortDescriptions =
                    {
                        new SortDescription("Value",ListSortDirection.Ascending)
                    }
            };
        Value = value;
    }
}

这是将保存数据的类,在这种情况下为int值,因为您只关心数字,所以这才是正确的数据类型,然后是ObservableCollection将保存子节点, CollectionView负责排序.

This is the class that will hold the data, in this case, an int Value, because you only care about numbers, so that's the right data type, and then an ObservableCollection that will hold the child nodes, and again the CollectionView that takes care of the sorting.

6::每当在WPF中使用DataBinding(这对于所有MVVM都是必不可少的)时,都需要实现INotifyPropertyChanged,所以这是PropertyChangedBase类,所有ViewModel都继承自: /p>

6: Whenever you use DataBinding in WPF (which is essential to all this MVVM thing) you need to implement INotifyPropertyChanged, so this is the PropertyChangedBase class All ViewModels inherit from:

public class PropertyChangedBase:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        Application.Current.Dispatcher.BeginInvoke((Action) (() =>
                                                                 {
                                                                     PropertyChangedEventHandler handler = PropertyChanged;
                                                                     if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
                                                                 }));
    }
}

并且只要有属性更改,您都需要通过以下方式通知它:

And wherever there's a change in a property you need to Notify that by doing:

OnPropertyChanged("PropertyName");

OnPropertyChanged("NewValueString");

这是结果:

  • 只需将我的所有代码复制并粘贴到File -> New Project -> WPF Application中,然后亲自查看结果.

  • Just copy and paste all my code in a File -> New Project -> WPF Application and see the results for yourself.

让我知道您是否需要我进行澄清.

Let me know if you need me to clarify anything.

这篇关于对C#中的TreeViewItems列表进行数字排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆