Atualize ligação do TreeViewItem usando o código? (XAML / WPF)
-
13-09-2019 - |
Pergunta
Eu tenho um TreeView
cuja ItemsSource
está definido para um modelo que eu tenho. 3 níveis de profundidade é um objeto cujo estado pode mudar e, em vez de escrever uma View e ViewModel para cada fase (muito demorado negócio) Eu queria apenas atualizar esse código usando.
Então, basicamente eu tenho um evento que é disparado uma vez as minhas actualizações modelo, eu pegá-lo, em seguida, encontrar o TreeViewItem
associado a este bit de dados. Meu problema agora é que não tenho idéia sobre como atualizar a ligação nele para refletir o novo valor!
alguém pode ajudar?
Eu sei que esta não é a melhor prática, mas eu realmente não quero ter que perder tempo escrevendo uma enorme quantidade de código para apenas atualizar uma coisa.
Graças Chris
Solução
Este exemplo funciona, mas é apenas dois (não 3) níveis de profundidade. Ela mostra um simples 2-TreeView nível hierárquico com itens pai A, B, e C, com as crianças numeradas (A.1, B.1, etc). Quando o botão Rename B.1 é clicado, ele renomeia B.1 para "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>
Este é um hack, mas re-avalia o DataTemplate cada vez que é ItemsSource alterações de propriedade.
O ideal seria implementar INotifyPropertyChanged em sua classe de objeto modelo que esta TreeViewItem é obrigado a, e tê-lo disparar o evento PropertyChanged quando esse valor muda. Na verdade, você deve ter cuidado para que você não está incorrer em um vazamento de memória porque ele não faz: Encontrando-memória vazamentos em aplicações WPF .
Outras dicas
Você tem certeza que não seria mais fácil de implementar INotifyPropertyChanged na classe relevante?
Parece que você pode precisar de dar uma olhada nos métodos UpdateSource
e UpdateTarget
.
referência MSDN para UpdateSource
Embora eu não estou totalmente certo de que isso vai funcionar quando você realmente obrigado ItemSource
do TreeView a uma estrutura hierárquica de dados, mas é onde eu iria começar a investigar.