@Naratzull
C#/C++ Developer

Как реализовать TreeView список с возможностью самостоятельного добавления в него элементов?

Дело вот в чем, я бы мог изначально написать логическую модель данных для TreeView и уже сюда вставить еë для примера, но сейчас такой возможности нет, поэтому просто еë представим. Пускай в ней будет что-то содержаться. Что именно - не так важно. Важными являются только выбранный корень (SelectedItem), выбранный дочерний элемент (SelectedSubItem) и коллекция всех элементов TreeView (Items). Сложность заключается в том, что мне нужно сделать так, чтобы дочерний элемент можно было добавлять к любому выбранному корню в TreeView по двум разным кнопкам. Одна выполняет роль создания основного элемента, другая дочеренего, а это два разных обработчика! Я попытался это провернуть, но у меня вышло так, что дочерний элемент создавался только для последнего в списке корня, а нужно для любого выбранного. Естественно, все элементы - это не пустышки, и как я в начале писал у всего этого есть своя модель данных. И я не понимаю как это можно реализовать. Прошу всех экспертов WPF и Шарпа помочь мне, ибо я полный чайник в таких вещах, а вопрос мучает уже полгода. Описание и название вопроса может быть «туманным» из-за отсутствия фрагментов кода, но если что-то нужно уточнить, то без проблем. Если честно, описать подобное чистым текстом - еще та проблема.

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;
    }
  • Вопрос задан
  • 278 просмотров
Решения вопроса 1
yarosroman
@yarosroman
C# the best
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. Использовать для привязываемых коллекций - ObservableCollection - умеет оповещать подписчика об изменении коллекции
2. WPF не умеет привязывает SelectedItem у TreeView, решения- https://stackoverflow.com/questions/7153813/wpf-mv... , https://tyrrrz.me/blog/wpf-treeview-selecteditem-t...
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы