Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 树景蓝调。我想选择一个项目_C#_Wpf_Treeview - Fatal编程技术网

C# 树景蓝调。我想选择一个项目

C# 树景蓝调。我想选择一个项目,c#,wpf,treeview,C#,Wpf,Treeview,我正在尝试选择一个TreeView项目。现在,我可以访问包含的TreeViewItem,并告诉它展开,以便选择它的孩子。如果已经展开,则一切正常,如果未展开,则运行以下代码: EventHandler selector = new EventHandler(delegate { if (selectedDirectoryTreeItem.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated

我正在尝试选择一个TreeView项目。现在,我可以访问包含的TreeViewItem,并告诉它展开,以便选择它的孩子。如果已经展开,则一切正常,如果未展开,则运行以下代码:

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);
    }