سؤال

انا املك 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>

الآن، من الكود الموجود خلف النافذة الرئيسية، أريد تحديد التيار TreeViewItem.ومع ذلك، إذا كنت تستخدم:

this.mainTreeList.SelectedItem;

العنصر المحدد من النوع MyTreeViewItemViewModel.لكنني أريد الحصول على "الوالد" أو "الملزم" TreeViewItem.أنا لا أنقل ذلك إلى بلدي TreeViewItemModel كائن (لن أعرف حتى كيف).

كيف يمكنني أن أفعل هذا؟

هل كانت مفيدة؟

المحلول

بيا Stollnitz الصورة دخول بلوق عن ذلك، حاول

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

نصائح أخرى

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

لا يعمل (بالنسبة لي) كـ mainTreeList.Items.CurrentPosition في عرض الشجرة باستخدام HierarchicalDataTemplate سيكون دائمًا -1.

لا يفعل أدناه كـ mainTreeList.Items.CurrentItem في عرض الشجرة باستخدام HierarchicalDataTemplate سيكون دائمًا فارغًا.

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

بدلاً من اضطررت إلى تعيين آخر TreeViewItem محدد في حدث TreeViewItem.Selected الموجه والذي يصل إلى عرض الشجرة (لا توجد TreeViewItem نفسها في وقت التصميم لأننا نستخدم HierarchicalDataTemplate).

يمكن التقاط الحدث في 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;

        ...
     }

وأنا واجهت نفس المشكلة. كنت بحاجة للحصول على TreeViewItem لدرجة أنني يمكن أن يكون أن تحديده. ثم أدركت أنني أستطيع أن مجرد إضافة خاصية IsSelected إلى بلدي ViewModel، وهو ما ثم منضمة إلى IsSelectedProperty TreeViewItems. ويمكن تحقيق ذلك مع 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>

والآن إذا أريد أن يكون عنصر في treeview اختيار، وأنا مجرد دعوة IsSelected على صفي ViewModel مباشرة.

ونأمل أن يساعد شخص ما.

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

وهذا يعمل على نحو أفضل بالنسبة لي.

مستوحاة من إجابة فيانور، حاولت أن أفعل TreeViewItem يمكن الوصول إليها بسهولة لكل عنصر بيانات أ TreeViewItem تم إنشاؤه ل.

الفكرة هي إضافة أ TreeViewItem- الحقل المكتوب في نموذج العرض، والذي يتم عرضه أيضًا عبر الواجهة، ويحتوي على TreeView ملؤها تلقائيا كلما TreeViewItem يتم إنشاء الحاوية.

يتم ذلك عن طريق التصنيف الفرعي TreeView وإرفاق حدث إلى ItemContainerGenerator, ، والذي يسجل TreeViewItem كلما تم إنشاؤه.تشمل Gotchas حقيقة ذلك TreeViewItemيتم إنشاؤها بتكاسل، لذلك قد لا يكون هناك واحد متاح حقًا في أوقات معينة.

منذ نشر هذه الإجابة، قمت بتطوير هذا بشكل أكبر واستخدمته لفترة طويلة في مشروع واحد.لا توجد مشكلات حتى الآن، بخلاف حقيقة أن هذا ينتهك 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; }
}

وحاول شيئا من هذا القبيل:

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

وحيد "ItemContainerGenerator.ContainerFromItem" أو دعوة "ItemContainerGenerator.ItemContainerGenerator 'لا يمكن العثور على TreeViewItem يرتبط بها من وجوه عرض شجرة، منذ انفصال عرض شجرة تحكم البند والبيانات شجرة عرض البند. فمن الضروري إنشاء دالة عودي إلى استخدام 'ItemContainerGenerator.ContainerFromItem "و" ItemContainerGenerator.ItemContainerGenerator، لتحديد TreeViewItem في عرض شجرة. مثال وظيفة متكررة يمكن أن تبدو مثل:

private TreeViewItem GetTreeViewItemFromObject(ItemContainerGenerator container, object tvio)
{
    var item = container.ContainerFromItem(tvio) as TreeViewItem;
    if (item != null)
    {
        return item;
    }

    for (int i = 0; i < container.Items.Count; i++)
    {
        var subContainer = (TreeViewItem)container.ContainerFromIndex(i);
        if (subContainer != null)
        {
            item = GetTreeViewItemFromObject(subContainer.ItemContainerGenerator, tvio);
            if (item != null)
            {
                return item;
            }
        }
    }

    return null;
}

ودعا اليه     فار الهدف = GetTreeViewItemFromObject (treeView.ItemContainerGenerator، البند)؛

وظيفة متكررة يعمل إلا بعد عرض الشجرة "ItemContainerGenerator.Status 'هو' ContainersGenerated. حتى خلال فترة عرض التهيئة، 'GetTreeViewItemFromObject "لا يعمل.

ولقد عدلت بحث وليام عودي إلى إصدار أكثر إحكاما:

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

واحد من شأنه أن يطلق عليه من خلال توفير ItemContainerGenerator على سبيل المثال تريفيف والكائن البيانات الهدف:

TreeViewItem tvi = GetTreeViewItemFromObject(treeView.ItemContainerGenerator, targetDataObject);

هل كنت في حاجة إلى TreeViewItem لأنك ذاهب لتعديل ما يتم عرضه؟ إذا كان هذا هو الحال، أنصح باستخدام نمط لتغيير الطريقة التي يتم بها عرض العنصر بدلا من استخدام التعليمات البرمجية الخلفية بدلا من مباشرة تعديل TreeViewItem. وينبغي أن يكون أمل أنظف.

إذا كان لديك للعثور على البند في الأطفال الأطفال قد تضطر إلى استخدام العودية مثل هذا

public bool Select(TreeViewItem item, object select) // recursive function to set item selection in treeview
{
    if (item == null)
        return false;
    TreeViewItem child = item.ItemContainerGenerator.ContainerFromItem(select) as TreeViewItem;
    if (child != null)
    {
        child.IsSelected = true;
        return true;
    }
    foreach (object c in item.Items)
    {
        bool result = Select(item.ItemContainerGenerator.ContainerFromItem(c) as TreeViewItem, select);
        if (result == true)
            return true;
    }
    return false;
}

وهنا هو الحل. rtvEsa هو تريفيف. HierarchicalDataTemplate هو قالب تريفيف العلامة تجعل consumation الحقيقي من العنصر الحالي. هذا البند لا يتم تحديده هو العنصر الحالي في شجرة التحكم التي تستخدم HierarchicalDataTemplate.

وItems.CurrentItem هو جزء من كوكتيلات شجرة الداخلية. كنت غير قادر على الحصول على العديد من وdiferent البيانات. على سبيل المثال Items.ParenItem جدا.

  <HierarchicalDataTemplate ItemsSource="{Binding ChildItems}">

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top