WPF ListView 绑定到集合 - 找到父扩展器

问题描述

我编写了一个显示绘图列表的应用程序,作为测试,我编写了一个小应用程序来显示我设想的工作方式。

该应用程序的工作原理:

  • 创建一个 browserItem 类,它具有名称属性、活动属性和三个级别的分组。

  • 一个WPF ListView绑定一个ObservableCollection,并使用ICollectionView来显示基于三层分组嵌套的列表视图中的browserItems

  • 当应用程序运行时,它会创建多个 browserItems,设置它们的名称和分组等,并在 ListView 中显示这些项目

这一切都很好。

作为测试,该应用程序有一个滑块,它根据滑块编号简单地将 browserItem 的 Active 属性设置为 true - 这会导致它在列表视图中以绿色突出显示,因为 Active 是字体背景的绑定属性.

我希望发生的是当它以绿色突出显示时,例程将自动展开所有扩展器,以便用户无需寻找即可看到突出显示的项目。

有什么办法可以获得浏览器项目的父扩展器吗?

代码可以在这里下载: https://drive.google.com/file/d/1MW-v2gqFtubhnZdKUYGglQLN3S5xnVB4/view?usp=sharing

浏览器项目类:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ListBoxTest3
{

    public partial class browserItem : viewmodelBase
    {
        /// <summary>
        /// browserItem represents a node on the browser treeview structure and relates to either a browser branch or a view / sheet
        /// </summary>

        //Group one nesting level
        private string _l1group;
        public string L1group
        {
            get
            {
                return _l1group;
            }
             set
            {
                _l1group = value;
                OnPropertyChanged(nameof(L1group));
            }
        }

        //Group two nesting level
        private string _l2group;
        public string L2group
        {
            get
            {
                return _l2group;
            }
            set
            {
                _l2group = value;
                OnPropertyChanged(nameof(L2group));
            }
        }

        //Group three nesting level
        private string _l3group;
        public string L3group
        {
            get
            {
                return _l3group;
            }
            set
            {
                _l3group = value;
                OnPropertyChanged(nameof(L3group));
            }
        }


        //Name
        private string _name;

        public string Name
        {
            get => _name;
            set
            {
                if (_name != value)
                {
                    _name = value;
                    OnPropertyChanged(nameof(Name));
                }
            }
        }


        //Active or _active = is bound to the active view highlight
        private bool _active;

        public bool Active
        {
            get => _active;
            set
            {
                if (value != _active)
                {
                    _active = value;
                    OnPropertyChanged(nameof(Active));
                }
            }
        }
    }
}

MainWindow.Xaml:

<Window x:Class="ListBoxTest3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ListBoxTest3"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="450"
        Width="400">

    <Grid>
        <StackPanel Orientation="Vertical">
            <StackPanel Orientation="Vertical">
                <StackPanel Orientation="Horizontal"
                            Margin="10">
                    <TextBlock Text="Filter: " />
                    <TextBox x:Name="FilterBoxText"
                             Width="330"
                             Text="{Binding browserItemFilter,UpdateSourceTrigger=PropertyChanged}" />
                </StackPanel>
                <StackPanel Orientation="Vertical">
                    <StackPanel Orientation="Horizontal"
                                Margin="10">
                        <TextBlock Text="Change Active to number: " />
                        <Slider x:Name="changeactive"
                                Width="210"
                                SmallChange="1"
                                ValueChanged="Slider_ValueChanged"
                                IsSnapToTickEnabled="True"
                                TickFrequency="1"
                                TickPlacement="Both">

                        </Slider>
                        <TextBlock x:Name="displayslider"
                                   Text="0" />
                    </StackPanel>
                </StackPanel>
            </StackPanel>
            <ListView Name="TreeViewSheets"
                      Margin="10,10,10"
                      Height="314"
                      ItemsSource="{Binding browserItemCollectionView}">

                <ListView.ItemTemplate>
                    <DataTemplate>

                        <WrapPanel>
                            <TextBlock Text="{Binding Name}">
                                <TextBlock.Style>
                                    <Style targettype="{x:Type TextBlock}">
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding Active}"
                                                         Value="true">
                                                <Setter Property="Background"
                                                        Value="YellowGreen" />
                                            </DataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                </TextBlock.Style>
                            </TextBlock>
                        </WrapPanel>

                    </DataTemplate>
                </ListView.ItemTemplate>

                <ListView.GroupStyle>
                    <GroupStyle>
                        <GroupStyle.ContainerStyle>
                            <Style targettype="{x:Type GroupItem}">
                                <Setter Property="Template">
                                    <Setter.Value>
                                        <ControlTemplate>

                                            <Expander>

                                                <Expander.Header>
                                                    <TextBlock Text="{Binding Name}"
                                                               FontWeight="Bold"
                                                               VerticalAlignment="Bottom" />
                                                </Expander.Header>
                                                <ItemsPresenter />
                                            </Expander>

                                        </ControlTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </GroupStyle.ContainerStyle>
                    </GroupStyle>
                </ListView.GroupStyle>

            </ListView>
        </StackPanel>
    </Grid>
</Window>

MainWindow.xaml 背后的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;

namespace ListBoxTest3
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>

    public partial class MainWindow : Window
    {
        MainWindowviewmodel store
        {
            get;
            set;
        }

        public MainWindow()
        {
            InitializeComponent();

            store = new MainWindowviewmodel();

            store.browser.Add(new browserItem() { Name = "Level 01 Plan",L1group = "Architectural",Active = true,L2group = "Floor Plans",L3group = "1:100" }); ;
            store.browser.Add(new browserItem() { Name = "Level 01 Plan",L1group = "Structural",Active = false,L3group = "1:20" });
            store.browser.Add(new browserItem() { Name = "Level 02 Plan",L3group = "1:100" });
            store.browser.Add(new browserItem() { Name = "Level 02 Plan",L3group = "1:100" });
            store.browser.Add(new browserItem() { Name = "Elevation East",L2group = "Elevations",L3group = "1:100" });
            store.browser.Add(new browserItem() { Name = "Elevation West",L3group = "1:20" });
            store.browser.Add(new browserItem() { Name = "Elevation north",L3group = "1:100" });
            store.browser.Add(new browserItem() { Name = "Section A-A",L2group = "Sections",L3group = "1:100" });
            store.browser.Add(new browserItem() { Name = "Section B-B",L3group = "1:100" });
            store.browser.Add(new browserItem() { Name = "Section C-C",L3group = "1:100" });
            store.browser.Add(new browserItem() { Name = "Main Section",L2group = "Main Sections",L3group = "1:100" });
            store.browser.Add(new browserItem() { Name = "Level 01 RCP",L2group = "Ceiling Plans",L3group = "1:100" });

            TreeViewSheets.DataContext = store;

            FilterBoxText.DataContext = store;

            //Set slider max value
            changeactive.Maximum = store.browser.Count() - 1;
        }

        private void Slider_ValueChanged(object sender,RoutedPropertyChangedEventArgs<double> e)
        {
            //When slider is moved,set the item in the list as active
            for (int f=0; f < store.browser.Count; f++)
            {
                if (f == changeactive.Value)
                {
                    store.browser[f].Active = true;
                    displayslider.Text = f.ToString();
                    TreeViewSheets.ScrollIntoView(store.browser[f]);
                }
                else
                {
                    store.browser[f].Active = false;
                }
            }
        }
    }
}

MainWindowviewmodel 类,它包含包含浏览器项目的 ObservableCollection。它还具有 MainWindowviewmodel 的构造函数,该构造函数使用 CollectionViewSource 进行分组 - 这会根据 browserItem 类的 L1Group、L2Group 和 L3Group 字段为 Listview 动态创建组扩展器:

    class MainWindowviewmodel : viewmodelBase
{
    public ICollectionView browserItemCollectionView { get; }

    private ObservableCollection<browserItem> _browser = new ObservableCollection<browserItem>();

    public ObservableCollection<browserItem> browser
    {
        get => _browser;
        set
        {
            if (value != _browser)
            {
                _browser = value;
                OnPropertyChanged(nameof(browser));
            }
        }
    }

    private string _browserItemFilter = string.Empty;
    public string browserItemFilter
    {
        get
        {
            return _browserItemFilter;
        }
        set
        {
            _browserItemFilter = value;
            OnPropertyChanged(nameof(browserItemFilter));
            browserItemCollectionView.Refresh();
        }
    }

    public MainWindowviewmodel()
    //Constructor
    {
        browserItemCollectionView = CollectionViewSource.Getdefaultview(_browser);

        //Set up filter
        browserItemCollectionView.Filter = FilterbrowserItems;

        //Set up grouping
        browserItemCollectionView.GroupDescriptions.Add(new PropertyGroupDescription(nameof(browserItem.L1group)));
        browserItemCollectionView.GroupDescriptions.Add(new PropertyGroupDescription(nameof(browserItem.L2group)));
        browserItemCollectionView.GroupDescriptions.Add(new PropertyGroupDescription(nameof(browserItem.L3group)));
    }

    private bool FilterbrowserItems(object obj)
    {
        if (obj is browserItem check)
        {
            return check.Name.Contains(browserItemFilter);
        }

        return false;
    }
}

解决方法

您可以将 </li> <li class="nav-item"><a class="nav-link" href="{% url 'about' %}">About</a></li> <li class="nav-item"><a class="nav-link" href="{% url 'all_hobby_products' %}">Book</a></li> 命名,然后通过其名称在组项的模板中查找或使用Expander遍历可视化树以查找VisualTreeHelper

Expander

查找并展开组中的所有 private void Slider_ValueChanged(object sender,RoutedPropertyChangedEventArgs<double> e) { //When slider is moved,set the item in the list as active for (int index = 0; index < store.Browser.Count; index++) { BrowserItem browserItem = store.Browser[index]; if (index == e.NewValue) { browserItem .Active = true; displayslider.Text = index.ToString(); TreeViewSheets.ScrollIntoView(browserItem); if (TryGetExpanderOfItem(browserItem,out Expander expander)) { expander.Active = true; } } else { browserItem.Active = false; } } } private bool TryGetExpanderOfItem(object browserItem,out Expander expander) { expander = null; CollectionViewGroup groupItem = this.TreeViewSheets.Items.Groups .OfType<CollectionViewGroup>() .FirstOrDefault(group => group.Items.Contains(browserItem)); if (groupItem == null) { return false; } var groupContainer = this.TreeViewSheets.ItemContainerGenerator.ContainerFromItem(groupItem) as Control; expander = groupContainer?.Template.FindName("GroupExpander",groupContainer) as Expander; return expander != null; } 元素

以下版本返回视觉树中从所选组项开始的所有 Expander 元素:

Expander

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...