Unable to set Custom TreeView's Selected Item in Treeview programmtically

139 views Asked by At

I created a WPF application where I create a list of items to be executed, as a Treeview. On a click event, I parse the ObservableCollection items one by one. This observableCollection is set as the DataContext for the treeview. When running the tests, I want to highlight the current running item in the Treeview.

I have the implemented following code, but the highlighting on the Treeview (visuallY) does not seem to happen. I checked that the "IsSelected" property does get set/unset as programmed.

I am not sure were I went wrong. Could you point out where the mistake is.

I have this class used as a DataContext to the TreeView (named mainTree).

class mytreefile : INotifyPropertyChanged
{
    private string _name { get; set; }
    
    public ObservableCollection <mytreefile> children { get; set; }
    
    bool? _isSelected = false;
    public bool? IsSelected
    {
        get { return _isSelected; }
        set { SetIsSelected(value); }
    }
    void SetIsSelected(bool? val)
    {
        _isSelected = val;
    }
    
    public mytreefile(string value)
    {
        _name = value;
        children = new ObservableCollection<mytreefile>();
    }
    
     void NotifyPropertyChanged(string info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

        public event PropertyChangedEventHandler PropertyChanged;
}

The XAML file is

<Grid.Resources>
    <ResourceDictionary>
        <HierarchicalDataTemplate x:Key="tvTemplate" ItemsSource="{Binding children, Mode=TwoWay}">
            <StackPanel Orientation="Horizontal">
                <ContentPresenter Content="{Binding _name, Mode=TwoWay}" Margin="2,0" />
            </StackPanel>
        </HierarchicalDataTemplate>
    </ResourceDictionary>
</Grid.Resources>

<TreeView x:Name="mainTree" Grid.Row="0" Grid.Column="0" Grid.RowSpan="4" Background="WhiteSmoke"
            Height="Auto" Width="Auto"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
            HorizontalContentAlignment="Stretch"                         
            Margin="1,0,2,0" SelectedItemChanged="mainTree_SelectedItemChanged"
            ItemTemplate="{StaticResource tvTemplate}" 
            ItemsSource="{Binding}" DataContext="{Binding nodes}">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="FontWeight" Value="Bold" />
                </Trigger>
                <Trigger Property="IsSelected" Value="False">
                    <Setter Property="FontWeight" Value="Normal" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>

And my MainWindow code is:

public partial class MainWindow : Window
{
    ObservableCollection<mytreefile> nodes = new ObservableCollection<mytreefile>();
    mytreefile mtf = null;
    Thread thThread = null;
    int gnCount = 0;
    
    private void LoadTree ()
    {
        mytreefile tf1 = new mytreefile("Group1");
        nodes.Add(tf1);
        
        mytreefile subtf1 = new mytreefile("Sub Item 1");
        mytreefile subtf2 = new mytreefile("Sub Item 2");
        mytreefile subtf3 = new mytreefile("Sub Item 3");
        mytreefile subtf4 = new mytreefile("Sub Item 4");
        
        tf1.children.Add(subtf1); tf1.children.Add(subtf2); tf1.children.Add(subtf3); tf1.children.Add(subtf4);
        
        maintree.DataContext = nodes;
    }
    
    private void OnButton1_click()
    {
        mtf = nodes.ElementAt(0);
        gnCount = 0;
        thThread = new Thread(new ThreadStart(this.myThread));
        thThread.Start();
    }
    public void myThread ()
    {
        for (int i = 0; i < 3; i++)
        {
            Thread.Sleep(1000);
            this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Send,
                            new Action(() => SetTreeItem(i)));
        }
    }
    
    public void SetTreeItem(int i)
    {   
        if (gnCount > 0) {
            mytreefile mtreeitem = mtf.children.ElementAt(gnCount-1);
            mtreeitem.IsSelected = false;
        }
        mytreefile mtreeitem = mtf.children.ElementAt(gnCount++);
        mtreeitem.IsSelected = true;
    }
}
1

There are 1 answers

0
Joseph On

The problem was with the "mytreefile" class. The below class works fine. The way the "IsSelected" implementation was done made the difference. Posting the code for reference.

class mytreefile : INotifyPropertyChanged
{
    private string _name { get; set; }
    
    public ObservableCollection <mytreefile> children { get; set; }
    
    private bool _isSelected;

    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            if (value != this._isSelected)
            {
                this._isSelected = value;
                NotifyPropertyChanged("IsSelected");
            }
        }
    }
    
    public mytreefile(string value)
    {
        _name = value;
        children = new ObservableCollection<mytreefile>();
    }
    
     void NotifyPropertyChanged(string info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

        public event PropertyChangedEventHandler PropertyChanged;
}