WPF树视图蓝色.我想选一件商品

本文关键字:一件 视图 蓝色 WPF | 更新日期: 2023-09-27 18:01:22

我正在尝试选择一个TreeViewItem。现在,我可以访问包含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树视图蓝色.我想选一件商品

我个人总是发现最简单的方法是将一个Selected属性粘贴到我的模型对象中,然后将TreeViewItem Selected属性绑定到模型的Selected属性。下面是一些代码:

模型
public class Data : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public Data()
    {
        DataItems = new List<Data>();
    }
    public string Name { get; set; }
    private bool _selected;
    public bool Selected
    {
        get { return _selected; }
        set
        {
            _selected = value;
            OnPropertyChanged("Selected");
        }
    }
    public List<Data> DataItems { get; set; }
    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

XAML

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

在我看来,这是WPF的一个bug,但是我已经遇到过同样的问题好几次了。我从不相信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);

痛苦我知道,但它有效。

谢谢你的帮助,我明白了。好吧,不管怎样,它是有效的,但我不完全确定为什么它之前没有…如果有人能告诉我,那就太好了……我结合了上面两种回答的元素,然后添加了一点使其有效。出于某种原因,无论我做什么,我不能选择TVI (TreeViewElement),如果它的父还没有展开,即使父TVI说它的内容是生成的,事实上,有内容我可以遍历。因此,我的解决方案是等待生成内容,然后遍历它们并找到我想要的内容。这对我来说真的很奇怪,我不能抓住一个容器,因为它的内容。咩。我的代码可以稍微重构一下,但这里是:(工作完美)

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