1 回答

TA貢獻(xiàn)1805條經(jīng)驗(yàn) 獲得超9個(gè)贊
左側(cè)的樹(目錄)具有根節(jié)點(diǎn)(例如“TextEditor”部分)。每個(gè)部分都包含設(shè)置類別(例如“格式”)。右側(cè)ListView
(設(shè)置視圖)的項(xiàng)目具有組標(biāo)題,其類別名稱與目錄名稱相匹配(例如,格式)。
1. 編輯以解決使用PropertyGroupDescription
假設(shè):
在 a 內(nèi)部存在一個(gè)
CollectionViewSource
定義?ResourceDictionary
并命名為CollectionViewSource。設(shè)置數(shù)據(jù)項(xiàng)具有屬性
SettingsCategoryName
(例如格式)。的
SettingsCategoryName
的SelectedItem
綁定?TreeView
到一個(gè)屬性SelectedSettingsCategoryName
查看.xaml:
<ResourceDictionary>
? <CollectionViewSource x:Key="CollectionViewSource" Source="{Binding Settings}">
? ? ? <CollectionViewSource.GroupDescriptions>
? ? ? ? <PropertyGroupDescription PropertyName="SettingsCategoryName"/>
? ? ? </CollectionViewSource.GroupDescriptions>
? </CollectionViewSource>
</ResourceDictionary>
<ListView x:Name="ListView" ItemsSource="{Binding Source={StaticResource CollectionViewSource}}">
? <ListView.GroupStyle>
? ? <GroupStyle>
? ? ? <GroupStyle.HeaderTemplate>
? ? ? ? <DataTemplate>
? ? ? ? ? <TextBlock FontWeight="Bold"
? ? ? ? ? ? ? ? ? ? ?FontSize="14"
? ? ? ? ? ? ? ? ? ? ?Text="{Binding Name}" />
? ? ? ? </DataTemplate>
? ? ? </GroupStyle.HeaderTemplate>
? ? </GroupStyle>
? </ListView.GroupStyle>
</ListView>
View.xaml.cs:
找到選定的類別并將其滾動(dòng)到視口的頂部。
// Scroll the selected section to top when the selected item has changed
private void ScrollToSection()
{
? CollectionViewSource viewSource = FindResource("CollectionViewSource") as CollectionViewSource;
? CollectionViewGroup selectedGroupItemData = viewSource
? ? .View
? ? .Groups
? ? .OfType<CollectionViewGroup>()
? ? .FirstOrDefault(group => group.Name.Equals(this.SelectedSettingsCategoryName));
? GroupItem selectedroupItemContainer = this.ListView.ItemContainerGenerator.ContainerFromItem(selectedGroupItemData) as GroupItem;
? ScrollViewer scrollViewer;
? if (!TryFindCildElement(this.ListView, out scrollViewer))
? {
? ? return;
? }
? // Subscribe to scrollChanged event?
? // because the scroll executed by `BringIntoView` is deferred.
? scrollViewer.ScrollChanged += ScrollSelectedGroupToTop;
? selectedGroupItemContainer?.BringIntoView();
}
private void ScrollSelectedGroupToTop(object sender, ScrollChangedEventArgs e)
{
? ScrollViewer scrollViewer;
? if (!TryFindCildElement(this.ListView, out scrollViewer))
? {
? ? return;
? }
? scrollViewer.ScrollChanged -= ScrollGroupToTop;
? var viewSource = FindResource("CollectionViewSource") as CollectionViewSource;
? CollectionViewGroup selectedGroupItemData = viewSource
? ? .View
? ? .Groups
? ? .OfType<CollectionViewGroup>()
? ? .FirstOrDefault(group => group.Name.Equals(this.SelectedSettingsCategoryName));
? var groupIndex = viewSource
? ? .View
? ? .Groups.IndexOf(selectedGroupItemData);
? var absoluteVerticalScrollOffset = viewSource
? ? .View
? ? .Groups
? ? .OfType<CollectionViewGroup>()
? ? .TakeWhile((group, index) => index < groupIndex)
? ? .Sum(group =>
? ? ? (this.ListView.ItemContainerGenerator.ContainerFromItem(group) as GroupItem)?.ActualHeight?
? ? ??? 0
? ? );
? scrollViewer.ScrollToVerticalOffset(absoluteVerticalScrollOffset);
}
// Generic method to find any `DependencyObject` in the visual tree of a parent element
private bool TryFindCildElement<TElement>(DependencyObject parent, out TElement resultElement) where TElement : DependencyObject
{
? resultElement = null;
? for (var childIndex = 0; childIndex < VisualTreeHelper.GetChildrenCount(parent); childIndex++)
? {
? ? DependencyObject childElement = VisualTreeHelper.GetChild(parent, childIndex);
? ? if (childElement is Popup popup)
? ? {
? ? ? childElement = popup.Child;
? ? }
? ? if (childElement is TElement)
? ? {
? ? ? resultElement = childElement as TElement;
? ? ? return true;
? ? }
? ? if (TryFindCildElement(childElement, out resultElement))
? ? {
? ? ? return true;
? ? }
? }
? return false;
}
您可以將此方法移至ListView派生類型中。然后將 a 添加到處理路由命令的CommandBindings新自定義中,例如。將 模板化為 a并讓它們發(fā)出命令以將節(jié)名稱傳遞給自定義.ListViewScrollToSectionRoutedCommandTreeViewItemsButtonCommandParameterListView
備注
由于使用PropertyGroupDescription
結(jié)果會(huì)產(chǎn)生混合數(shù)據(jù)類型的項(xiàng)目源(GroupItemData
對(duì)于組標(biāo)頭以及實(shí)際數(shù)據(jù)項(xiàng)目),因此托管的 UI 虛擬化ItemsControl
已禁用且不可能(。在這種情況下,附加屬性ScrollViewer.CanContentScroll
會(huì)自動(dòng)設(shè)置為False
(強(qiáng)制)。對(duì)于大列表來說,這可能是一個(gè)巨大的缺點(diǎn),也是采用替代方法的原因。
2.替代解決方案(支持UI虛擬化)
當(dāng)涉及到實(shí)際設(shè)置結(jié)構(gòu)的設(shè)計(jì)時(shí),存在多種可能的變化。它可以是一棵樹,其中每個(gè)類別標(biāo)題節(jié)點(diǎn)都有自己的子節(jié)點(diǎn),這些子節(jié)點(diǎn)表示類別的設(shè)置,也可以是一個(gè)平面列表結(jié)構(gòu),其中類別標(biāo)題和設(shè)置都是同級(jí)的。為了使示例簡單起見,我選擇第二個(gè)選項(xiàng):平面列表數(shù)據(jù)結(jié)構(gòu)。
2.1 設(shè)置
基本思想:使用具有兩個(gè)級(jí)別的
模板進(jìn)行模板化。第二層(葉子)和共享標(biāo)題項(xiàng)的相同實(shí)例(見下文)。因此,選定的標(biāo)題項(xiàng)目引用了完全相同的項(xiàng)目標(biāo)題- 無需搜索。TreeView
HierarchicalDataTemplate
TreeView
ListView
IHeaederData
TreeView
ListView
實(shí)施概述:
您需要兩個(gè)
ItemsControl
元素:帶有節(jié)根節(jié)點(diǎn)(例如“文本編輯器”)
以及該部分的設(shè)置類別標(biāo)題子節(jié)點(diǎn)(葉節(jié)點(diǎn))(例如“字體”、“格式”)
TreeView
左側(cè)導(dǎo)航窗格有?兩層一個(gè)
ListView
用于實(shí)際設(shè)置及其類別標(biāo)題。
然后設(shè)計(jì)數(shù)據(jù)類型來表示設(shè)置、設(shè)置標(biāo)頭和節(jié)根節(jié)點(diǎn)
讓它們都實(shí)現(xiàn)一個(gè)
IData
具有共享屬性的共同點(diǎn)(例如標(biāo)頭)讓設(shè)置頭數(shù)據(jù)類型實(shí)現(xiàn)一個(gè)額外的?
IHeaderData
讓設(shè)置數(shù)據(jù)類型實(shí)現(xiàn)一個(gè)額外的
ISettingData
讓父節(jié)節(jié)點(diǎn)數(shù)據(jù)類型(根節(jié)點(diǎn))用于實(shí)現(xiàn)具有子節(jié)點(diǎn)類型的
TreeView
附加節(jié)點(diǎn)ISectionData
IHeaderData
創(chuàng)建項(xiàng)目源集合(所有類型
IEnumerable<IData>
)TreeView
一個(gè)用于(僅保存類別)的每個(gè)父節(jié)節(jié)點(diǎn),aSectionCollection
類型ISectionData
每個(gè)類別一個(gè),一個(gè)
CategoryCollection
類型IHeaderData
單個(gè)用于設(shè)置數(shù)據(jù)和共享類別(標(biāo)題數(shù)據(jù)),a
SettingCollection
類型IData
逐節(jié)填充已排序的源集合
將類型的節(jié)數(shù)據(jù)實(shí)例添加到的
ISectionData
源集合中SectionCollection
TreeView
將類型的共享類別數(shù)據(jù)頭實(shí)例添加
IHeaderData
到兩個(gè)源集合中CategoryCollection
,并且SettingCollection
將 type 的設(shè)置實(shí)例添加
ISettingData
到唯一SettingCollection
的對(duì)當(dāng)前部分的所有類別重復(fù)最后兩個(gè)步驟
將 分配給根節(jié)點(diǎn)
CategoryCollection
的子集合ISectionData
對(duì)所有部分重復(fù)這些步驟(及其類別和相應(yīng)的設(shè)置)
將 綁定
SectionCollection
到?TreeView
將 綁定
SettingsCollection
到LIstView
HierarchicalDataTemplate
為TreeView
數(shù)據(jù)創(chuàng)建一個(gè)ISectionData
類型為根的數(shù)據(jù)創(chuàng)建兩個(gè)
DataTemplate
用于ListView
一個(gè)目標(biāo)
IHeaderData
一個(gè)目標(biāo)
ISettingData
邏輯:
當(dāng)選擇?
IHeaderData
其中的一項(xiàng)時(shí)TreeView
ListView
使用獲取此數(shù)據(jù)項(xiàng)的項(xiàng)目容器var container = ItemsContainerGenerator.GetContainerFromItem(selectedTreeViewCategoryItem)
將容器滾動(dòng)到視圖中
container.BringIntoView()
(實(shí)現(xiàn)視圖外的虛擬化項(xiàng)目)將容器滾動(dòng)到視圖頂部
因?yàn)?code>TreeView和ListView
共享相同的類別標(biāo)題數(shù)據(jù) (?IHeaderData
),所以所選項(xiàng)目很容易跟蹤和查找。您不必搜索設(shè)置組。您可以使用參考直接跳轉(zhuǎn)到該組。這意味著數(shù)據(jù)的結(jié)構(gòu)是解決方案的關(guān)鍵。
- 1 回答
- 0 關(guān)注
- 249 瀏覽
添加回答
舉報(bào)