Rob
Rob

Reputation: 638

C# wpf mvvm identify selected node in treeview with button click

I just want to identify the selected node on my treeview when I click button on my tree, please consider the image below:

enter image description here

Treeview is bound to viewmodel and I have a property to hold such value when you click the plus button the value for the selected node should be set. The only time that the selected value is set when you click on "sample node" first before you click the plus button. Below is the code for my xaml:

<TreeView x:Name="tree" ItemsSource="{Binding SectorTree, Mode=OneWay}" MinHeight="150">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Children, Mode=OneTime}">
            <StackPanel Orientation="Horizontal">
                <Button HorizontalAlignment="Center" Command="{Binding SelectedItemChangedCommand, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                            ToolTip="Edit sector name" Background="Transparent" BorderThickness="0">
                    <Button.Content>
                        <Image Width="14" Height="14" Margin="0,0,0,0" Source="path_of_image" />
                    </Button.Content>
                </Button>
                <ContentPresenter Content="{Binding SectorName, Mode=OneTime}" Margin="2,0" />
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsSelected" Value="{Binding IsSelected,  Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>

Upvotes: 0

Views: 1180

Answers (2)

Peregrine
Peregrine

Reputation: 4546

It's not clear what problem you're trying to solve by adding this button to the TreeView data template.

The TreeView already has a SelectedItemChanged event, and a SelectedItem property.

The alternative is to use a Behavior to add a new bindable BoundSelectedItem property to the Treeiew. This will return the data item class, not a TreeViewItem instance.

public class perTreeViewHelper : Behavior<TreeView>
{
    public object BoundSelectedItem
    {
        get => GetValue(BoundSelectedItemProperty);
        set => SetValue(BoundSelectedItemProperty, value);
    }

    public static readonly DependencyProperty BoundSelectedItemProperty =
        DependencyProperty.Register("BoundSelectedItem",
            typeof(object),
            typeof(perTreeViewHelper),
            new FrameworkPropertyMetadata(null,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnBoundSelectedItemChanged));

    private static void OnBoundSelectedItemChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        if (args.NewValue is perTreeViewItemViewModelBase item)
            item.IsSelected = true;
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged;
        base.OnDetaching();
    }

    private void OnTreeViewSelectedItemChanged(object obj, RoutedPropertyChangedEventArgs<object> args)
    {
        BoundSelectedItem = args.NewValue;
    }
}

More details on my recent blog post.

Upvotes: 1

PeterE
PeterE

Reputation: 1

This is how I solved the same problem in the Click event of the buttons in the TreeView.

  1. Add a 'Me' property to the MyNodeClass that is bound to each TreeView node:

    public object Me { get { return this; } }
    
  2. Bind the Tag property of the Button to Me:

    Button Tag="{Binding Me}" Click="Button_Click"
    
  3. Find the instance in the Button_Click(object sender...) event:

    MyNodeClass x = ((Button)sender).Tag as MyNodeClass
    

Upvotes: 0

Related Questions