C# 树景蓝调。我想选择一个项目
我正在尝试选择一个TreeView项目。现在,我可以访问包含的TreeViewItem,并告诉它展开,以便选择它的孩子。如果已经展开,则一切正常,如果未展开,则运行以下代码:C# 树景蓝调。我想选择一个项目,c#,wpf,treeview,C#,Wpf,Treeview,我正在尝试选择一个TreeView项目。现在,我可以访问包含的TreeViewItem,并告诉它展开,以便选择它的孩子。如果已经展开,则一切正常,如果未展开,则运行以下代码: EventHandler selector = new EventHandler(delegate { if (selectedDirectoryTreeItem.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated
EventHandler selector = new EventHandler(delegate
{
if (selectedDirectoryTreeItem.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
TreeViewItem want = selectedDirectoryTreeItem.ItemContainerGenerator.ContainerFromItem(dirWeWantSelected) as TreeViewItem;
if (want == null)
return;
want.IsSelected = true;
// selectedDirectoryTreeItem.ItemContainerGenerator.StatusChanged -= selector;
}
});
selectedDirectoryTreeItem.ItemContainerGenerator.StatusChanged += selector;
所以我的问题是,为什么它不选择?想要总是空的。我正在搜索互联网,寻找另一种方法,但如果有人能向我解释一下,那就太好了。在我看来,这是WPF中的一个错误,但我已经多次遇到相同的问题。我从不信任ItemContainerGenerator的状态,而是在单独的线程上循环:
private void _selectTreeViewHelper(object directory) {
TreeViewItem want = null;
bool broke = false; //probably some sort of wait timeout instead, but works for sake of example
while (true) {
Dispatcher.Invoke(new Action(delegate {
want = selectedDirectoryTreeItem.ItemContainerGenerator.ContainerFromItem(directory) as TreeViewItem;
if (want != null && want.IsLoaded) {
want.IsSelected = true;
broke = true;
}
}));
if (broke) { break; }
Thread.Sleep(100);
}
}
那就叫它:
var thread = new Thread(new ParameterizedThreadStart(_selectTreeViewHelper));
thread.Start(dirWeWantSelected);
痛苦我知道,但它是有效的 我个人一直认为,将选定属性粘贴到模型对象中,然后将TreeViewItem选定属性绑定到模型的选定属性是最简单的。下面是一些代码: 模型
公共类数据:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
公共数据()
{
DataItems=新列表();
}
公共字符串名称{get;set;}
选择私人布尔;
公共图书馆获选
{
获取{return\u selected;}
设置
{
_所选=值;
OnPropertyChanged(“选定”);
}
}
公共列表数据项{get;set;}
私有void OnPropertyChanged(字符串propertyName)
{
if(PropertyChanged!=null)
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
}
XAML
代码隐藏
public partial class Window1 : Window
{
private Random _random;
private List<Data> _dataItems;
public Window1()
{
InitializeComponent();
_dataItems = Init();
_tvTest.ItemsSource = _dataItems;
_random = new Random(5);
}
private List<Data> Init()
{
List<Data> dataItems = new List<Data>();
for (int i = 1; i <= 10; i++)
{
Data d1 = new Data();
d1.Name = "Data:" + i.ToString();
for (int j = 1; j <= 4; j++)
{
Data d2 = new Data();
d2.Name = "Data:" + i.ToString() + j.ToString();
d1.DataItems.Add(d2);
}
dataItems.Add(d1);
}
return dataItems;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
int index = _random.Next(0, 9);
int subIndex = _random.Next(0, 3);
if (subIndex == 0)
_dataItems[index].Selected = true;
else
_dataItems[index].DataItems[subIndex - 1].Selected = true;
}
}
公共部分类窗口1:窗口
{
私人随机(u Random),;
私有列表_数据项;
公共窗口1()
{
初始化组件();
_dataItems=Init();
_tvTest.ItemsSource=\u数据项;
_随机=新随机(5);
}
私有列表Init()
{
列表数据项=新列表();
对于(int i=1;i谢谢你的帮助,我找到了它。好吧,它无论如何都能工作,但我不完全确定为什么以前没有…如果有人能告诉我这会很好…我有点结合了上面两个回答的元素,然后加上一点使它工作。出于某种原因,无论我做什么,我都不能选择TVI(树元素)如果它的父级还没有扩展,即使父级TVI说它的内容已经生成,事实上,有我可以迭代的内容。因此,我的解决方案是等待内容生成,然后再遍历它们,找到我想要的内容。对于我来说,真的很奇怪,我不能仅仅抓住一个给定内容的容器。M呃,我的代码可以进行一点重构,但现在是:(工作非常完美)
IsSelected设置为true,当用户自动单击treeview项时,我不知道您想做什么。您应该以MVVM的方式进行操作。mdm20的答案显示了使用MVVM模式使用WPF treeview的示例。我想回答ItemContainerGenerator的问题,而MVVM方法更好处理这种特殊情况的方法,并不总是100%适用。我遇到过许多需要访问实际控件的情况,我不能简单地绑定到备份模型。但我不希望在启动时自动展开所有内容。我知道父树项是,我知道绑定到Tr的对象eeViewItem我想要选中。我需要它来工作,无论东西是否已经展开。取出isExpanded setter属性似乎会使它变得僵硬。移除isExpanded setter不会影响任何东西。不确定为什么您认为移除它会破坏任何东西。您可以在模型中创建一个展开的属性,并将其与所选属性完全相同不需要控制扩展的内容。TVI的内部是异步加载的,因此,扩展TVI并立即查看其内部是不起作用的。您的代码会使所有内容都以扩展的方式开始,而这只是不起作用。我需要扩展必要的TVI,等待其内容生成,然后从内部选择TVI。删除isExpanded会破坏它,因为您的代码不必担心等待生成内容。您可以自己尝试。或者查看Adam的答案,他说的更正确。我从visual studio剪切并粘贴了代码…它对我很好,无论是否扩展。很高兴您找到了您的答案。
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:controls="clr-namespace:MyControls;assembly=MyControls"
Title="Window1">
<Window.Resources>
<Style x:Key="CustomTreeViewItem" TargetType="TreeViewItem">
<Setter Property="IsSelected" Value="{Binding Path=Selected, Mode=TwoWay}" />
<Setter Property="IsExpanded" Value="True" />
</Style>
</Window.Resources>
<DockPanel Background="Transparent">
<TreeView x:Name="_tvTest" DockPanel.Dock="Left" ItemContainerStyle="{StaticResource CustomTreeViewItem}" Width="300" >
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Data}" ItemsSource="{Binding DataItems}">
<TextBlock Text="{Binding Name}" Padding="2" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Padding="2" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<Button Content="Select Random TreeView Item" Click="Button_Click" Height="50" Width="200" />
</DockPanel>
</Window>
public partial class Window1 : Window
{
private Random _random;
private List<Data> _dataItems;
public Window1()
{
InitializeComponent();
_dataItems = Init();
_tvTest.ItemsSource = _dataItems;
_random = new Random(5);
}
private List<Data> Init()
{
List<Data> dataItems = new List<Data>();
for (int i = 1; i <= 10; i++)
{
Data d1 = new Data();
d1.Name = "Data:" + i.ToString();
for (int j = 1; j <= 4; j++)
{
Data d2 = new Data();
d2.Name = "Data:" + i.ToString() + j.ToString();
d1.DataItems.Add(d2);
}
dataItems.Add(d1);
}
return dataItems;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
int index = _random.Next(0, 9);
int subIndex = _random.Next(0, 3);
if (subIndex == 0)
_dataItems[index].Selected = true;
else
_dataItems[index].DataItems[subIndex - 1].Selected = true;
}
}
public void listItemClickClick(object sender, RoutedEventArgs e)
{
try
{
UserFile fil = (UserFile)(sender as ListBoxItem).DataContext;
MessageBox.Show("to do: download stuff");
return;
}
catch (InvalidCastException)
{
}
try
{
dirWeWantSelected = (Directory)(sender as ListBoxItem).DataContext;
}
catch (InvalidCastException)
{
MessageBox.Show("this should never happen");
}
selectedDirectoryTreeItem.IsExpanded = true;
TreeViewItem want = null;
try
{
want = selectedDirectoryTreeItem.ItemContainerGenerator.ContainerFromItem(dirWeWantSelected) as TreeViewItem;
}
catch
{
MessageBox.Show("weird error");
}
if (want != null)
{
want.IsSelected = true;
}
else
{
selectedDirectoryTreeItem.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
}
}
void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
if (selectedDirectoryTreeItem.ItemContainerGenerator.Status
== System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
{
selectedDirectoryTreeItem.ItemContainerGenerator.StatusChanged
-= ItemContainerGenerator_StatusChanged;
Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Input,
new Action(DelayedAction));
}
}
void DelayedAction()
{
selectedDirectoryTreeItem.Items.MoveCurrentToFirst();
Directory curr;
do
{
curr = (Directory)selectedDirectoryTreeItem.Items.CurrentItem;
if (curr.id == dirWeWantSelected.id)
{
curr.Selected = true;
return;
}
selectedDirectoryTreeItem.Items.MoveCurrentToNext();
}
while (selectedDirectoryTreeItem.Items.CurrentItem != null);
}