2011-07-07 17 views
1

TreeViewItemを選択しようとしています。今、私はTreeViewItemを含んでいるものへのアクセス権を持っているので、私はその子供を選択できるように展開するように言った。それはすでにすべてが、うまくある、それは私がこのコードを実行しない場合は、拡張だ場合:wpfツリービューのブルース。アイテムを選択したい

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; 

だから私の質問は、なぜ文句を言わないそれは選択しますか? wantは常にnullです。私はこれを行うための別の方法を探しているinterwebsを洗い流しているが、誰かが私にこれを説明することができれば涼しいだろう

+0

ユーザーがTreeViewItemを自動的にクリックしたときにIsSelectedがtrueに設定されていますが、私はあなたがしようとしているものを取得しません。 – anivas

答えて

0

おかげ背後に、私はそれを考え出しました。とにかくそれはとにかく働くが、私はそれが前になかった理由を完全には分かっていない。だれかがそれが素敵だろうと私に言うことができたら...私はちょっと上記の2つの反応の要素を組み合わせて、それは働く。何らかの理由で、親のTVIがそのコンテンツが生成されていて、実際にコンテンツを再生できたとしても、親がまだ展開されていない場合は、TVI(TreeViewElement)を選択することはできません。私の解決策は、コンテンツが生成されるのを待ってから、それらを介して評価し、私が望むものを見つけることでした。私が本当に奇妙なのは、私はちょうど内容を与えられたコンテナをつかむことができないということです。 Meh。

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

私の意見では、これはWPFのバグですが、 。

var thread = new Thread(new ParameterizedThreadStart(_selectTreeViewHelper)); 
thread.Start(dirWeWantSelected); 

痛みは私が知っているが、それは動作します:

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

は次にそれを呼び出す:私は、次のようないるItemContainerGeneratorのステータスとは別のスレッドに代わりにループを信頼することはありません。

+0

MVVMのやり方を検討する必要があります。 mdm20の答えは、MVVMパターンを使用してWPFツリービューを使用する例を示しています。 – alimbada

+0

私はItemContainerGeneratorの質問に答えようとしていましたが、MVVMアプローチはこの特定のシナリオを処理するより良い方法ですが、常に100%適用可能というわけではありません。私は実際のコントロールにアクセスする必要がある多くの状況に遭遇しました。バッキングモデルに単純にバインドすることはできません。 – Adam

+0

それは動作しません...それはTreeViewItemを選択することはありません... – Sheena

2

私は、自分のモデルオブジェクトに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

私はすべてが起動時に自動的に展開されたいのではありません。私は、親のTreeViewItemがあり、私は選択したいTreeViewItemにバインドされているオブジェクトを知っている。私は、ものがすでに拡張されているかどうかにかかわらず、それが必要です。 isExpandedセッタープロパティを取り出すことはそれを撫でるようです – Sheena

+0

isExpandedセッターを削除しても何も影響しません。なぜそれを取り除くと何が壊れたと思うのか分かりません。モデルでExpandedプロパティを作成し、Selectedプロパティとまったく同じように扱い、展開されているものを制御できます。 – mdm20

+0

TVIの内部は非同期にロードされるため、TVIを拡張してすぐに内部を見ることは機能しません。あなたのコードでは、すべてのことが始まります。私は必要なTVIを拡張し、そのコンテンツが生成されるのを待ってから、その中からTVIを選択する必要があります。 isExpandedを削除すると、コードがコンテンツが生成されるのを待つことを心配しないため、破損します。自分で試してみてください。または、アダムの答えをチェックして、彼はもっと正しい軌道に乗っていた。 – Sheena

関連する問題