根据嵌套类型使用自定义加载方法延迟加载 TreeViewItem
Lazy Loading TreeViewItem with custom loading method depending on their nested type
假设我有 collection 名员工。员工可以是高级主管、初级主管或实习生。
这 3 种类型的员工是 类 从 employee 派生的。每个高级主管指导一组初级主管。每个初级主管指导一组学员。
LoadChilds
填写Childs
Collection.
现在我想通过使用延迟初始化在树视图中显示他们从高级到实习生的层次结构。我想在 TreeViewItem.Exapand
事件上调用方法 LoadChilds
。 (我对其他想法持开放态度。)
目前我正在通过 HierarchicalDataTemplate 呈现不同的数据类型。
<TreeView x:Name="Tree">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type model:Supervisor}" ItemsSource="{Binding Childs}">
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type model:Employee}" ItemsSource="{Binding Childs}">
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
问题:如何在展开 TreeViewItem 时调用方法、编辑数据并刷新 UI?
您可以定义一个接口,A
和 B
都实现并将扩展的 TreeViewItem
的 DataContext
转换为这种类型:
public interface ICommon
{
string Name { get; set; }
void LoadChilds(DBConnection connection);
}
public class A : ICommon
{
public class A()
{
Childs = new ObservableCollection<B>();
}
public string Name { get; set; }
public ObservableCollection<B> Childs { get; set; }
public void LoadChilds(DBConnection connection) //Type is unimportant
{
// adding childs
}
}
public class B : ICommon
{
public class B()
{
Childs = new ObservableCollection<B>(); //Yes, rekursiv
}
public string Name { get; set; }
public ObservableCollection<B> Childs { get; set; }
public void LoadChilds(DBConnection connection)
{
// adding childs
}
}
private void TreeView_Expanded(object sender, RoutedEventArgs e)
{
TreeViewItem tvi = e.OriginalSource as TreeViewItem;
ICommon obj = tvi.DataContext as ICommon;
if (obj != null)
obj.LoadChilds(...);
}
绝对有一种 "prettier" 方法 - 无需在代码隐藏的事件处理程序中编写业务逻辑。
在视图模型 类 中引入布尔值 IsExpanded
,将 TreeViewItem.IsExpanded
绑定到 属性 并触发 setter 中的 LoadChilds
方法:
<TreeView x:Name="Tree">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding Path=IsExpanded, Mode=TwoWay}"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type model:A}" ItemsSource="{Binding Childs}">
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type model:B}" ItemsSource="{Binding Childs}">
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
public class A
{
public A()
{
// null is a placeholder.
// without any items TreeViewItem will not even show expander
// (Expand event won't work either)
Childs = new ObservableCollection<B>() { null };
}
public string Name { get; set; }
private bool _isExpanded;
public bool IsExpanded
{
get
{
return _isExpanded;
}
set
{
_isExpanded = value;
// when node is expanded, RELOAD!
if (_isExpanded)
LoadChilds();
}
}
public ObservableCollection<B> Childs { get; set; }
public void LoadChilds()
{
Childs.Clear();
Childs.Add(new B() { Name = Guid.NewGuid().ToString() });
}
}
B
在这个测试示例中几乎相同,但我想 LoadChilds 逻辑在真实应用程序中会有所不同
public class B
{
public B()
{
Childs = new ObservableCollection<B>() { null };
}
public string Name { get; set; }
private bool _isExpanded;
public bool IsExpanded
{
get
{
return _isExpanded;
}
set
{
_isExpanded = value;
if (_isExpanded)
LoadChilds();
}
}
public ObservableCollection<B> Childs { get; set; }
public void LoadChilds()
{
Childs.Clear();
Childs.Add(new B() { Name = Guid.NewGuid().ToString() });
}
}
假设我有 collection 名员工。员工可以是高级主管、初级主管或实习生。 这 3 种类型的员工是 类 从 employee 派生的。每个高级主管指导一组初级主管。每个初级主管指导一组学员。
LoadChilds
填写Childs
Collection.
现在我想通过使用延迟初始化在树视图中显示他们从高级到实习生的层次结构。我想在 TreeViewItem.Exapand
事件上调用方法 LoadChilds
。 (我对其他想法持开放态度。)
目前我正在通过 HierarchicalDataTemplate 呈现不同的数据类型。
<TreeView x:Name="Tree">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type model:Supervisor}" ItemsSource="{Binding Childs}">
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type model:Employee}" ItemsSource="{Binding Childs}">
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
问题:如何在展开 TreeViewItem 时调用方法、编辑数据并刷新 UI?
您可以定义一个接口,A
和 B
都实现并将扩展的 TreeViewItem
的 DataContext
转换为这种类型:
public interface ICommon
{
string Name { get; set; }
void LoadChilds(DBConnection connection);
}
public class A : ICommon
{
public class A()
{
Childs = new ObservableCollection<B>();
}
public string Name { get; set; }
public ObservableCollection<B> Childs { get; set; }
public void LoadChilds(DBConnection connection) //Type is unimportant
{
// adding childs
}
}
public class B : ICommon
{
public class B()
{
Childs = new ObservableCollection<B>(); //Yes, rekursiv
}
public string Name { get; set; }
public ObservableCollection<B> Childs { get; set; }
public void LoadChilds(DBConnection connection)
{
// adding childs
}
}
private void TreeView_Expanded(object sender, RoutedEventArgs e)
{
TreeViewItem tvi = e.OriginalSource as TreeViewItem;
ICommon obj = tvi.DataContext as ICommon;
if (obj != null)
obj.LoadChilds(...);
}
绝对有一种 "prettier" 方法 - 无需在代码隐藏的事件处理程序中编写业务逻辑。
在视图模型 类 中引入布尔值 IsExpanded
,将 TreeViewItem.IsExpanded
绑定到 属性 并触发 setter 中的 LoadChilds
方法:
<TreeView x:Name="Tree">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding Path=IsExpanded, Mode=TwoWay}"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type model:A}" ItemsSource="{Binding Childs}">
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type model:B}" ItemsSource="{Binding Childs}">
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
public class A
{
public A()
{
// null is a placeholder.
// without any items TreeViewItem will not even show expander
// (Expand event won't work either)
Childs = new ObservableCollection<B>() { null };
}
public string Name { get; set; }
private bool _isExpanded;
public bool IsExpanded
{
get
{
return _isExpanded;
}
set
{
_isExpanded = value;
// when node is expanded, RELOAD!
if (_isExpanded)
LoadChilds();
}
}
public ObservableCollection<B> Childs { get; set; }
public void LoadChilds()
{
Childs.Clear();
Childs.Add(new B() { Name = Guid.NewGuid().ToString() });
}
}
B
在这个测试示例中几乎相同,但我想 LoadChilds 逻辑在真实应用程序中会有所不同
public class B
{
public B()
{
Childs = new ObservableCollection<B>() { null };
}
public string Name { get; set; }
private bool _isExpanded;
public bool IsExpanded
{
get
{
return _isExpanded;
}
set
{
_isExpanded = value;
if (_isExpanded)
LoadChilds();
}
}
public ObservableCollection<B> Childs { get; set; }
public void LoadChilds()
{
Childs.Clear();
Childs.Add(new B() { Name = Guid.NewGuid().ToString() });
}
}