36

TreeView使用しHierarchicalDataTemplateてデータをバインドする があります。

次のようになります。

<TreeView x:Name="mainTreeList" ItemsSource="{Binding MyCollection}>
  <TreeView.Resources>
    <HierarchicalDataTemplate 
     DataType="{x:Type local:MyTreeViewItemViewModel}" 
     ItemsSource="{Binding Children}">
      <!-- code code code -->
    </HierarchicalDataTemplate>
  </TreeView.Resources>
</TreeView>

ここで、たとえばメイン ウィンドウのコード ビハインドから、現在の selected を取得したいと考えていますTreeViewItem。ただし、使用する場合:

this.mainTreeList.SelectedItem;

selectedItem のタイプはMyTreeViewItemViewModelです。しかし、「親」または「バインド」を取得したいTreeViewItem。私はそれを私のTreeViewItemModelオブジェクトに渡しません(方法さえ知りません)。

これどうやってするの?

4

11 に答える 11

32
TreeViewItem item = (TreeViewItem)(mainTreeList
    .ItemContainerGenerator
    .ContainerFromIndex(mainTreeList.Items.CurrentPosition));

HierarchicalDataTemplate を使用するツリービューの mainTreeList.Items.CurrentPosition は常に -1 であるため、(私にとっては) 機能しません

HierarchicalDataTemplate を使用するツリービューの mainTreeList.Items.CurrentItem は常に null になるため、以下のいずれも行いません。

TreeViewItem item = (TreeViewItem)mainTreeList
    .ItemContainerGenerator
    .ContainerFromItem(mainTreeList.Items.CurrentItem);

代わりに、ルーティングされた TreeViewItem.Selected イベントで最後に選択された TreeViewItem を設定する必要がありました。これは、ツリー ビューにバブルアップします (HierarchicalDataTemplate を使用しているため、設計時に TreeViewItem 自体は存在しません)。

イベントは、次のように XAML でキャプチャできます。

<TreeView TreeViewItem.Selected="TreeViewItemSelected" .../> 

次に、最後に選択された TreeViewItem を次のようにイベントに設定できます。

    private void TreeViewItemSelected(object sender, RoutedEventArgs e)
    {
        TreeViewItem tvi = e.OriginalSource as TreeViewItem;

        // set the last tree view item selected variable which may be used elsewhere as there is no other way I have found to obtain the TreeViewItem container (may be null)
        this.lastSelectedTreeViewItem = tvi;

        ...
     }
于 2010-07-05T04:59:02.210 に答える
24

これに関するBea Stollnitzのブログエントリから、試してみてください

TreeViewItem item = (TreeViewItem)(mainTreeList
    .ItemContainerGenerator
    .ContainerFromIndex(mainTreeList.Items.CurrentPosition));
于 2009-03-06T03:03:08.020 に答える
9

私はこの同じ問題に遭遇しました。選択できるように、TreeViewItem にアクセスする必要がありました。次に、プロパティ IsSelected を ViewModel に追加するだけでよいことに気付き、それを TreeViewItems IsSelectedProperty にバインドしました。これは、ItemContainerStyle で実現できます。

<TreeView>
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                </Style>
            </TreeView.ItemContainerStyle>
</TreeView>

ツリービュー内の項目を選択したい場合は、ViewModel クラスで IsSelected を直接呼び出すだけです。

それが誰かを助けることを願っています。

于 2011-09-21T17:20:45.803 に答える
7
TreeViewItem item = (TreeViewItem)(mainTreeList
    .ItemContainerGenerator
    .ContainerFromIndex(mainTreeList.Items.CurrentPosition)); gives first item in the TreeView because CurrentPosition is always 0.

どうですか

TreeViewItem item = (TreeViewItem)(mainTreeList
    .ItemContainerGenerator
    .ContainerFromItem(mainTreeList.SelectedItem)));

これは私にとってはうまくいきます。

于 2013-01-09T10:39:21.077 に答える
4

Fëanor の回答に触発されて、作成されTreeViewItemたすべてのデータ項目に簡単にアクセスできるようにしTreeViewItemました。

アイデアは、TreeViewItem型指定されたフィールドをビューモデルに追加し、これもインターフェイスを介して公開し、コンテナが作成さTreeViewれるたびに自動的に入力することです。TreeViewItem

これは、イベントをサブクラス化TreeViewして にアタッチすることによって行われます。これは、作成されるたびにItemContainerGeneratorを記録します。TreeViewItem落とし穴には、 が遅延して作成されるという事実が含まれているTreeViewItemため、特定の時間に使用できるものがない可能性があります。

この回答を投稿して以来、私はこれをさらに発展させ、1 つのプロジェクトで長い間使用してきました。これがMVVMに違反しているという事実を除いて、これまでのところ問題はありません(ただし、単純なケースではボイラープレートを大量に節約できます)。ソースはこちら

使用法

選択したアイテムの親を選択して折りたたんで、それがビューにあることを確認します。

...
var selected = myTreeView.SelectedItem as MyItem;
selected.Parent.TreeViewItem.IsSelected = true;
selected.Parent.TreeViewItem.IsExpanded = false;
selected.Parent.TreeViewItem.BringIntoView();
...

宣言:

<Window ...
        xmlns:tvi="clr-namespace:TreeViewItems"
        ...>
    ...
    <tvi:TreeViewWithItem x:Name="myTreeView">
        <HierarchicalDataTemplate DataType = "{x:Type src:MyItem}"
                                  ItemsSource = "{Binding Children}">
            <TextBlock Text="{Binding Path=Name}"/>
        </HierarchicalDataTemplate>
    </tvi:TreeViewWithItem>
    ...
</Window>
class MyItem : IHasTreeViewItem
{
    public string Name { get; set; }
    public ObservableCollection<MyItem> Children { get; set; }
    public MyItem Parent;
    public TreeViewItem TreeViewItem { get; set; }
    ...
}

コード

public class TreeViewWithItem : TreeView
{
    public TreeViewWithItem()
    {
        ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
    }

    private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
    {
        var generator = sender as ItemContainerGenerator;
        if (generator.Status == GeneratorStatus.ContainersGenerated)
        {
            int i = 0;
            while (true)
            {
                var container = generator.ContainerFromIndex(i);
                if (container == null)
                    break;

                var tvi = container as TreeViewItem;
                if (tvi != null)
                    tvi.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;

                var item = generator.ItemFromContainer(container) as IHasTreeViewItem;
                if (item != null)
                    item.TreeViewItem = tvi;

                i++;
            }
        }
    }
}

interface IHasTreeViewItem
{
    TreeViewItem TreeViewItem { get; set; }
}
于 2012-03-26T13:33:13.073 に答える
2

次のようなことを試してください:

    public bool UpdateSelectedTreeViewItem(PropertyNode dateItem, ItemsControl itemsControl)
    {
        if (itemsControl == null || itemsControl.Items == null || itemsControl.Items.Count == 0)
        {
            return false;
        }
        foreach (var item in itemsControl.Items.Cast<PropertyNode>())
        {
            var treeViewItem = itemsControl.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
            if (treeViewItem == null)
            {
                continue;
            }
            if (item == dateItem)
            {
                treeViewItem.IsSelected = true;
                return true;
            }
            if (treeViewItem.Items.Count > 0 && UpdateSelectedTreeViewItem(dateItem, treeViewItem))
            {
                return true;
            }
        }
        return false;
    }
于 2015-02-07T05:04:01.247 に答える
1

William の再帰検索をよりコンパクトなバージョンに変更しました。

public TreeViewItem GetTreeViewItemFromObject(ItemContainerGenerator container, object targetObject) {
    if (container.ContainerFromItem(targetObject) is TreeViewItem target) return target;
    for (int i = 0; i < container.Items.Count; i++)
        if ((container.ContainerFromIndex(i) as TreeViewItem)?.ItemContainerGenerator is ItemContainerGenerator childContainer)
            if (GetTreeViewItemFromObject(childContainer, targetObject) is TreeViewItem childTarget) return childTarget;
    return null;
}

TreeView インスタンスの ItemContainerGenerator とターゲット データ オブジェクトを提供することで、それを呼び出すことができます。

TreeViewItem tvi = GetTreeViewItemFromObject(treeView.ItemContainerGenerator, targetDataObject);
于 2019-01-11T19:46:07.273 に答える
0

表示されているものを変更するので、TreeViewItem が必要ですか? その場合は、TreeViewItem を直接変更する代わりにコード ビハインドを使用する代わりに、Style を使用して項目の表示方法を変更することをお勧めします。うまくいけば、よりきれいになるはずです。

于 2009-09-22T02:47:08.580 に答える
0

これが解決策です。rtvEsa はツリービューです。HierarchicalDataTemplate は、現在のアイテムを実際に消費するツリービュー テンプレート タグです。これは選択されたアイテムではなく、HierarchicalDataTemplate を使用するツリー コントロールの現在のアイテムです。

Items.CurrentItem は内部ツリー コレクションの一部です。多くの異なるデータを取得することはできません。たとえば、Items.ParenItem も。

  <HierarchicalDataTemplate ItemsSource="{Binding ChildItems}">

  <TextBox Tag="{Binding ElementName=rtvEsa, Path=Items.CurrentItem }" />

于 2014-10-09T07:28:38.410 に答える