A
A
Alex Gorbunov2020-10-11 20:13:54
WPF
Alex Gorbunov, 2020-10-11 20:13:54

How to implement a TreeView list with the ability to independently add elements to it?

The thing is, I could initially write a logical data model for the TreeView and insert it here for an example, but now there is no such possibility, so let's just imagine it. Let it contain something. What exactly is not so important. Only the selected root (SelectedItem), the selected child (SelectedSubItem), and the collection of all TreeView items (Items) are important. The difficulty lies in the fact that I need to make it so that a child element can be added to any selected root in the TreeView by two different buttons. One performs the role of creating the main element, the other child, and these are two different handlers! I tried to turn it around, but it turned out that the child element was created only for the last root in the list, but it needs to be for any selected one. Naturally, all elements are not empty shells, and as I wrote at the beginning, all this has its own data model. And I don't understand how it can be done. I ask all WPF experts and Sharpe to help me, because I am a complete noob in such things, and the question has been tormenting me for half a year. The description and title of the question may be "vague" due to the lack of code snippets, but if something needs to be clarified, then no problem. To be honest, describing this in plain text is another problem.

UPD:

public class RootModel
    {
        public string Name { get; set; }
        public List<SubRootModel> SubRoots { get; } = new List<SubRootModel>();
        public string Text { get; set; }
    }

    public class SubRootModel
    {
        public string Name { get; set; }
        public RootModel Parent { get; set; }
        public string Text { get; set; }
    }

    public class TreeViewModel : INotifyPropertyChanged
    {
        private RootModel _selectedRoot = new RootModel();
        private SubRootModel _selectedSubRoot = new SubRootModel();

        public List<RootModel> Items { get; } = new List<RootModel>();

        public RootModel SelectedRoot
        {
            get => _selectedRoot;
            set
            {
                _selectedRoot = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedRoot)));
            }
        }

        public SubRootModel SelectedSubRoot
        {
            get => _selectedSubRoot;
            set
            {
                _selectedSubRoot = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedSubRoot)));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

Answer the question

In order to leave comments, you need to log in

1 answer(s)
R
Roman, 2020-10-12
@Naratzull

public class TreeNode
    {
        public int ParentId { get; set; }
        public string Name { get; set; }
        public ObservableCollection<TreeNode> Children { get; set; }
    }

    public class TreeViewModel
    {
        public ObservableCollection<TreeNode> Nodes { get; set; }

        public TreeNode SelectedNode { get; set; }
    }

    public partial class MainWindow : Window
    {
        public TreeViewModel model { get; set; }

        private int i = 1;

        public MainWindow()
        {
            InitializeComponent();

            model = new TreeViewModel();

            model.Nodes = new ObservableCollection<TreeNode>();
            this.DataContext = model;

            model.Nodes.Add(new TreeNode() { Name = "Root", Children = new ObservableCollection<TreeNode>() });
            model.Nodes.FirstOrDefault().Children.Add(new TreeNode() { Name = "Second" });

        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if (model.SelectedNode != null)
            {
                model.SelectedNode.Children.Add(new TreeNode() { Name = "Children "+i.ToString(), Children = new ObservableCollection<TreeNode>() });
            }
            else
            {
                model.Nodes.Add(new TreeNode() { Name = "Root "+i.ToString(), Children = new ObservableCollection<TreeNode>() });
            }
            i++;
        }

        private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            model.SelectedNode = (TreeNode)e.NewValue;
        }
    }

<Grid>
        <TreeView HorizontalAlignment="Left" Height="337" Margin="42,34,0,0" VerticalAlignment="Top" Width="303" ItemsSource="{Binding Path=Nodes}">
            <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Children}">
          <TextBlock Text="{Binding Name}" />
        </HierarchicalDataTemplate>
      </TreeView.ItemTemplate>
        </TreeView>
        <Button Content="Button" HorizontalAlignment="Left" Margin="374,34,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    </Grid>

1. Use for bindable collections - ObservableCollection - can notify the subscriber about a change in the collection
2. WPF can't bind SelectedItem from TreeView, solutions - https://stackoverflow.com/questions/7153813/wpf-mv... , https:// tyrrrz.me/blog/wpf-treeview-selecteditem-t...

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question