views:

406

answers:

3

Hey

I have a TreeView whose ItemsSource is set to a Model I have. 3 levels deep is an object whose state can change and, rather than write a View and ViewModel for each stage (very lengthy business) I wanted to just update this using code.

So basically I have an event that is fired once my model updates, I catch it then find the TreeViewItem associated with this bit of data. My issue now is I have NO idea on how to update the binding on it to reflect the new value!

Can anyone help?

I know this isn't best practice but I really don't want to have to waste time writing a massive amount of code to just update one thing.

Thanks Chris

A: 

Sounds like you might need to take a look at the UpdateSource and UpdateTarget methods.

MSDN reference for UpdateSource

Although I'm not totally sure this will work when you've actually bound the TreeView's ItemSource to a hierarchical data structure, but it's where I would start investigating.

Sam Meldrum
+1  A: 

Are you sure it wouldn't be easier to implement INotifyPropertyChanged on the relevant class?

Coder 42
A: 

This example works, though it's only two (not 3) levels deep. It shows a simple 2-level hierarchical treeview with parent items A, B, and C, with numbered children (A.1, B.1, etc). When the Rename B.1 button is clicked, it renames B.1 to "Sylvia".

using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

namespace UpdateVanillaBindingValue
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private DataClass _data;

        public Window1()
        {
            InitializeComponent();
            var data = CreateData();
            DataContext = _data = data;
        }

        private DataClass CreateData()
        {
            return new DataClass
               {
                   Parents=new List<Parent>
                       {
                           new Parent{Name="A",Children=new List<Child>{new Child{Name="A.0"},new Child{Name="A.1"}}},
                           new Parent{Name="B",Children=new List<Child>{new Child{Name="B.0"},new Child{Name="B.1"},new Child{Name="B.2"}}},
                           new Parent{Name="C",Children=new List<Child>{new Child{Name="C.0"},new Child{Name="C.1"}}}
                       }
               };
        }

        private void Rename_Click(object sender, RoutedEventArgs e)
        {
            var parentB = _data.Parents[1];
            var parentBItem = TheTree.ItemContainerGenerator.ContainerFromItem(parentB) as TreeViewItem;
            parentB.Children[1].Name = "Sylvia";

            var parentBItemsSource = parentBItem.ItemsSource;
            parentBItem.ItemsSource = null;
            parentBItem.ItemsSource = parentBItemsSource;
        }
    }

    public class DataClass
    {
        public List<Parent> Parents { get; set; }
    }

    public class Parent
    {
        public string Name { get; set; }
        public List<Child> Children { get; set; }
    }

    public class Child
    {
        public string Name { get; set; }
    }
}

<Window x:Class="UpdateVanillaBindingValue.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <Grid.Resources>
            <DataTemplate x:Key="ChildTemplate">
                <TextBlock Margin="50,0,0,0" Text="{Binding Name}" />
            </DataTemplate>
            <HierarchicalDataTemplate x:Key="ParentTemplate" ItemsSource="{Binding Children}" ItemTemplate="{StaticResource ChildTemplate}">
                <TextBlock Text="{Binding Name}" />
            </HierarchicalDataTemplate>
        </Grid.Resources>
        <TreeView x:Name="TheTree" ItemsSource="{Binding Parents}" ItemTemplate="{StaticResource ParentTemplate}" />
        <Button VerticalAlignment="Bottom" HorizontalAlignment="Center" Content="Rename B.1" Click="Rename_Click" />
    </Grid>
</Window>

This is a hack, but it re-evaluates the DataTemplate every time it's ItemsSource property changes.

Ideally, you would implement INotifyPropertyChanged on your model object class that this TreeViewItem is bound to, and have it fire the PropertyChanged event when that value changes. In fact, you should be careful that you aren't incurring a memory leak because it doesn't: Finding memory-leaks in WPF Applications.

Tim Erickson
Thanks, I have already tried this and it doesnt work on a treeitem level only if I do it to the entire treeview, which means I lose my selected item
Chris
Try the revised example - it works on my machine ;-) The key was cycling the ItemsSource on the parent TreeViewItem rather than the DataContext on the TreeView.
Tim Erickson