wpf treeview блюз.Я хочу выбрать предмет - PullRequest
2 голосов
/ 07 июля 2011

Я пытаюсь выбрать 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;  

Итак, мой вопрос, почему он не выбирает? хочу всегда ноль. Я прочесываю сети в поисках другого способа сделать это, но было бы здорово, если бы кто-нибудь мог мне это объяснить

Ответы [ 3 ]

2 голосов
/ 07 июля 2011

Лично мне всегда было проще вставить свойство 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;
    }
}
0 голосов
/ 12 июля 2011

Спасибо за помощь, разобрался. Ну, в любом случае это работает, но я не совсем уверен, почему это не было раньше ... если кто-нибудь может сказать мне, что это было бы прекрасно ... Я как бы соединил элементы двух ответов выше, а затем добавил немного, чтобы сделать это работает. По какой-то причине, независимо от того, что я делаю, я не могу выбрать 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);
    }
0 голосов
/ 07 июля 2011

На мой взгляд, это ошибка в WPF, но я сталкивался с одной и той же проблемой несколько раз.Я никогда не доверяю Status 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);

Боль, я знаю, но это работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...