How to programmatically set selected node of a treeview in 1803 version

budding_developer 136 Reputation points
2020-04-03T06:40:34.897+00:00

I am using a treeview in my uwp project which supports 1803 version. I need to know how to set the selected node of the treeview programmatically. Also it would be helpful if solution is provided in C#. Thanks in advance.

Universal Windows Platform (UWP)
No comments
{count} votes

Accepted answer
  1. Peter Fleischer (former MVP) 17,586 Reputation points
    2020-04-03T09:33:22.67+00:00

    Hi, try following demo:

    XAML:

    <Page
        x:Class="App1.Page06"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App06"
        xmlns:i="using:Microsoft.Xaml.Interactivity"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
      <Page.DataContext>
        <local:ViewModel/>
      </Page.DataContext>
      <StackPanel>
        <Button Content="Select Node" Command="{Binding Cmd}"/>
        <TreeView SelectionMode="Multiple" Height="400">
          <i:Interaction.Behaviors>
            <local:TvBehavior/>
          </i:Interaction.Behaviors>
        </TreeView>
      </StackPanel>
    </Page>
    

    and code:

    using Microsoft.Xaml.Interactivity;
    using System;
    using System.Windows.Input;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    
    namespace App06
    {
      public class ViewModel
      {
        Random rnd = new Random();
    
        public ICommand Cmd
        {
          get => new RelayCommand((state) =>
          {
            var n = TreeV.RootNodes[rnd.Next(0, TreeV.RootNodes.Count)];
            if (rnd.NextDouble() > .5 && n.HasChildren)
            {
              n.IsExpanded = true;
              n = n.Children[rnd.Next(0, n.Children.Count)];
            }
            //TreeV.SelectedNodes.Clear();
            TreeV.SelectedNodes.Add(n);
          });
        }
    
        public TreeView TreeV { get; set; }
    
            internal void LoadTree()
        {
          for (int i = 1; i < 10; i++)
          {
            var n = new TreeViewNode() { Content = $"Node {i}" };
            TreeV.RootNodes.Add(n);
            for (int k = 1; k < 10; k++) n.Children.Add(new TreeViewNode() { Content = $"SubNode {i} {k}" });
          }
        }
      }
    
      public class TvBehavior : Behavior<TreeView>
      {
        protected override void OnAttached() => AssociatedObject.Loaded += AssociatedObject_Loaded;
        private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
        {
          var vm = AssociatedObject.DataContext as ViewModel;
          if (vm == null) return;
          vm.TreeV = AssociatedObject;
          vm.LoadTree();
        }
      }
    
      public class RelayCommand : ICommand
      {
        private readonly Predicate<object> _canExecute;
        private readonly Action<object> _execute;
        public event EventHandler CanExecuteChanged;
        public RelayCommand(Action<object> execute) : this(execute, null) { }
        public RelayCommand(Action<object> execute, Predicate<object> canExecute) { _execute = execute; _canExecute = canExecute; }
        public bool CanExecute(object parameter) => (_canExecute == null) ? true : _canExecute(parameter);
        public void Execute(object parameter) => _execute(parameter);
        public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
      }
    }
    

1 additional answer

Sort by: Most helpful
  1. Richard Zhang-MSFT 6,921 Reputation points
    2020-04-03T08:17:29.847+00:00

    Hello,​

    Welcome to our Microsoft Q&A platform!

    We can usually set TreeView's selected item by binding.

    This is a simple idea:

    1. Create a data class, which contains a property to control whether it is selected

    public class Model : INotifyPropertyChanged
    {
        public string Name { get; set; }
        public bool _isSelected;
        public bool IsSelected
        {
            get => _isSelected;
            set
            {
                _isSelected = value;
                OnPropertyChanged();
            }
        }
        public List<Model> Children { get; set; }
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged([CallerMemberName]string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    2. Create a data collection as a data source

    private ObservableCollection<SupportTopic> TopicCollection = new ObservableCollection<SupportTopic>();
    

    3. Create the corresponding DataTemplate and bind the corresponding properties

    <TreeView x:Name="MyTreeView"
          ItemsSource="{x:Bind TopicCollection}">
        <TreeView.ItemTemplate>
            <DataTemplate x:DataType="local:Model">
                <TreeViewItem Content="{x:Bind Name}"
                              ItemsSource="{x:Bind Children}"
                              IsSelected="{x:Bind IsSelected,Mode=OneWay}"
                              />
            </DataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
    

    In this case, if you need to set an item in the list as a selected item, you only need to set the corresponding Model.IsSelected to True.

    Thanks.