diff --git a/src/Wpf.Ui.Gallery/ViewModels/Pages/Collections/ListViewScrollViewModel.cs b/src/Wpf.Ui.Gallery/ViewModels/Pages/Collections/ListViewScrollViewModel.cs new file mode 100644 index 000000000..408de9957 --- /dev/null +++ b/src/Wpf.Ui.Gallery/ViewModels/Pages/Collections/ListViewScrollViewModel.cs @@ -0,0 +1,23 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +namespace Wpf.Ui.Gallery.ViewModels.Pages.Collections; + +public sealed partial class ListViewScrollViewModel : ViewModel +{ + [ObservableProperty] + private ObservableCollection _bigArray = GenerateBigArray(); + + private static ObservableCollection GenerateBigArray() + { + var result = new ObservableCollection(); + for (int i = 0; i < 500; i++) + { + result.Add($"Item {i + 1}"); + } + + return result; + } +} diff --git a/src/Wpf.Ui.Gallery/ViewModels/Pages/Collections/ListViewViewModel.cs b/src/Wpf.Ui.Gallery/ViewModels/Pages/Collections/ListViewViewModel.cs index 34ef73a3a..4bf8d5db4 100644 --- a/src/Wpf.Ui.Gallery/ViewModels/Pages/Collections/ListViewViewModel.cs +++ b/src/Wpf.Ui.Gallery/ViewModels/Pages/Collections/ListViewViewModel.cs @@ -28,6 +28,19 @@ public int ListViewSelectionModeComboBoxSelectedIndex [ObservableProperty] private ObservableCollection _basicListViewItems = GeneratePersons(); + [ObservableProperty] + private ObservableCollection _bigArray = GenerateBigArray(); + + private static ObservableCollection GenerateBigArray() + { + var result = new ObservableCollection(); + for (int i = 0; i < 500; i++) + { + result.Add($"Item {i + 1}"); + } + return result; + } + private static ObservableCollection GeneratePersons() { var random = new Random(); diff --git a/src/Wpf.Ui.Gallery/ViewModels/Windows/MainWindowViewModel.cs b/src/Wpf.Ui.Gallery/ViewModels/Windows/MainWindowViewModel.cs index 57bbb17d5..1884badc0 100644 --- a/src/Wpf.Ui.Gallery/ViewModels/Windows/MainWindowViewModel.cs +++ b/src/Wpf.Ui.Gallery/ViewModels/Windows/MainWindowViewModel.cs @@ -75,6 +75,7 @@ public partial class MainWindowViewModel(IStringLocalizer localize new NavigationViewItem(nameof(System.Windows.Controls.DataGrid), typeof(DataGridPage)), new NavigationViewItem(nameof(ListBox), typeof(ListBoxPage)), new NavigationViewItem(nameof(Ui.Controls.ListView), typeof(ListViewPage)), + new NavigationViewItem("ListViewNoPageScroll", typeof(ListViewScrollPage)), new NavigationViewItem(nameof(TreeView), typeof(TreeViewPage)), #if DEBUG new NavigationViewItem("TreeList", typeof(TreeListPage)), diff --git a/src/Wpf.Ui.Gallery/Views/Pages/Collections/ListViewScrollPage.xaml b/src/Wpf.Ui.Gallery/Views/Pages/Collections/ListViewScrollPage.xaml new file mode 100644 index 000000000..2016af3d4 --- /dev/null +++ b/src/Wpf.Ui.Gallery/Views/Pages/Collections/ListViewScrollPage.xaml @@ -0,0 +1,41 @@ + + + + + + + + + + + + diff --git a/src/Wpf.Ui.Gallery/Views/Pages/Collections/ListViewScrollPage.xaml.cs b/src/Wpf.Ui.Gallery/Views/Pages/Collections/ListViewScrollPage.xaml.cs new file mode 100644 index 000000000..41920928c --- /dev/null +++ b/src/Wpf.Ui.Gallery/Views/Pages/Collections/ListViewScrollPage.xaml.cs @@ -0,0 +1,30 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +using System.Windows; +using System.Windows.Controls; +using Wpf.Ui.Controls; +using Wpf.Ui.Gallery.ControlsLookup; +using Wpf.Ui.Gallery.ViewModels.Pages.Collections; + +namespace Wpf.Ui.Gallery.Views.Pages.Collections; +/// +/// Interaction logic for ListViewScrollPage.xaml +/// +[GalleryPage("Selectable list.", SymbolRegular.GroupList24)] +public partial class ListViewScrollPage : INavigableView +{ + /// + public ListViewScrollViewModel ViewModel { get; set; } + + public ListViewScrollPage(ListViewScrollViewModel viewModel) + { + ViewModel = viewModel; + DataContext = this; + + InitializeComponent(); + } + +} diff --git a/src/Wpf.Ui.Tray/Controls/NotifyIcon.cs b/src/Wpf.Ui.Tray/Controls/NotifyIcon.cs index 57197c7c2..729fe56f7 100644 --- a/src/Wpf.Ui.Tray/Controls/NotifyIcon.cs +++ b/src/Wpf.Ui.Tray/Controls/NotifyIcon.cs @@ -486,8 +486,8 @@ private void RegisterHandlers() private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { - // Menu?.DataContext = e.NewValue; - if (Menu != null) + // Update ContextMenu DataContext when NotifyIcon DataContext changes + if (Menu != null && e.NewValue != null) { Menu.DataContext = e.NewValue; } diff --git a/src/Wpf.Ui/Controls/NavigationView/NavigationView.AttachedProperties.cs b/src/Wpf.Ui/Controls/NavigationView/NavigationView.AttachedProperties.cs index 854580ef9..cea588276 100644 --- a/src/Wpf.Ui/Controls/NavigationView/NavigationView.AttachedProperties.cs +++ b/src/Wpf.Ui/Controls/NavigationView/NavigationView.AttachedProperties.cs @@ -45,6 +45,41 @@ private static void OnHeaderContentChanged(DependencyObject d, DependencyPropert public static void SetHeaderContent(FrameworkElement target, object? headerContent) => target.SetValue(HeaderContentProperty, headerContent); + // ============================================================ + // IsScrollable Attached Property + // ============================================================ + + /// + /// Identifies the attached property. + /// + public static readonly DependencyProperty IsScrollableProperty = DependencyProperty.RegisterAttached( + "IsScrollable", + typeof(bool), + typeof(NavigationView), + new FrameworkPropertyMetadata(true) + ); + + /// + /// Gets the value of the attached property for a specified element. + /// + /// The element from which to read the property value. + /// if the content of the page hosted in should be scrollable; otherwise, . + [AttachedPropertyBrowsableForType(typeof(DependencyObject))] + public static bool GetIsScrollable(DependencyObject element) + { + return (bool)element.GetValue(IsScrollableProperty); + } + + /// + /// Sets the value of the attached property for a specified element. + /// + /// The element on which to set the property value. + /// The value to set. to disable scrolling on the content presenter. + public static void SetIsScrollable(DependencyObject element, bool value) + { + element.SetValue(IsScrollableProperty, value); + } + // ============================================================ // NavigationParent Attached Property // ============================================================ diff --git a/src/Wpf.Ui/Controls/NavigationView/NavigationView.Navigation.cs b/src/Wpf.Ui/Controls/NavigationView/NavigationView.Navigation.cs index a4dfefdef..56dcb1c52 100644 --- a/src/Wpf.Ui/Controls/NavigationView/NavigationView.Navigation.cs +++ b/src/Wpf.Ui/Controls/NavigationView/NavigationView.Navigation.cs @@ -7,6 +7,7 @@ using System.Collections.ObjectModel; using System.Diagnostics; +using System.Windows.Controls; using Wpf.Ui.Abstractions; // ReSharper disable once CheckNamespace @@ -382,10 +383,33 @@ System.Windows.Navigation.NavigationEventArgs e _ = frame.RemoveBackEntry(); + // Update content ScrollViewer based on page's IsScrollable property + UpdateContentScrollViewer(e.Content); + /*var replaced = 1; ((NavigationViewContentPresenter)sender).JournalOwnership =*/ } + private void UpdateContentScrollViewer(object? content) + { + if (ContentScrollViewer is null) + { + return; + } + + var isScrollable = true; + + if (content is DependencyObject dependencyObject) + { + isScrollable = NavigationView.GetIsScrollable(dependencyObject); + } + + ContentScrollViewer.SetCurrentValue( + ScrollViewer.VerticalScrollBarVisibilityProperty, + isScrollable ? ScrollBarVisibility.Auto : ScrollBarVisibility.Disabled + ); + } + private void AddToNavigationStack( INavigationViewItem viewItem, bool addToNavigationStack, diff --git a/src/Wpf.Ui/Controls/NavigationView/NavigationView.TemplateParts.cs b/src/Wpf.Ui/Controls/NavigationView/NavigationView.TemplateParts.cs index b0aa2436f..99fa3460d 100644 --- a/src/Wpf.Ui/Controls/NavigationView/NavigationView.TemplateParts.cs +++ b/src/Wpf.Ui/Controls/NavigationView/NavigationView.TemplateParts.cs @@ -6,7 +6,10 @@ // Based on Windows UI Library // Copyright(c) Microsoft Corporation.All rights reserved. +using System.Windows.Controls; + // ReSharper disable once CheckNamespace + namespace Wpf.Ui.Controls; /// @@ -30,10 +33,11 @@ namespace Wpf.Ui.Controls; Name = TemplateElementAutoSuggestBoxSymbolButton, Type = typeof(System.Windows.Controls.Button) )] +[TemplatePart(Name = TemplateElementContentScrollViewer, Type = typeof(ScrollViewer))] public partial class NavigationView { /// - /// Template element represented by the PART_MenuItemsItemsControl name. + /// Template element represented by the PART_NavigationViewContentPresenter name. /// private const string TemplateElementNavigationViewContentPresenter = "PART_NavigationViewContentPresenter"; @@ -63,6 +67,11 @@ public partial class NavigationView /// private const string TemplateElementAutoSuggestBoxSymbolButton = "PART_AutoSuggestBoxSymbolButton"; + /// + /// Template element represented by the PART_ContentScrollViewer name. + /// + private const string TemplateElementContentScrollViewer = "PART_ContentScrollViewer"; + /// /// Gets or sets the control responsible for rendering the content. /// @@ -93,6 +102,11 @@ public partial class NavigationView /// protected System.Windows.Controls.Button? AutoSuggestBoxSymbolButton { get; set; } + /// + /// Gets or sets the that hosts the content of the . + /// + protected ScrollViewer? ContentScrollViewer { get; set; } + /// public override void OnApplyTemplate() { @@ -121,6 +135,11 @@ public override void OnApplyTemplate() { NavigationViewContentPresenter.Navigated -= OnNavigationViewContentPresenterNavigated; NavigationViewContentPresenter.Navigated += OnNavigationViewContentPresenterNavigated; + + // We need to wait for the NavigationViewContentPresenter to apply its template + // so we can find the ContentScrollViewer + NavigationViewContentPresenter.ApplyTemplate(); + FindContentScrollViewer(); } if ( @@ -151,6 +170,20 @@ is System.Windows.Controls.Button autoSuggestBoxSymbolButton } } + private void FindContentScrollViewer() + { + if (NavigationViewContentPresenter?.Template is null) + { + return; + } + + // Try to find the ContentScrollViewer within the NavigationViewContentPresenter's template + if (NavigationViewContentPresenter.Template.FindName(TemplateElementContentScrollViewer, NavigationViewContentPresenter) is ScrollViewer scrollViewer) + { + ContentScrollViewer = scrollViewer; + } + } + protected T GetTemplateChild(string name) where T : DependencyObject { diff --git a/src/Wpf.Ui/Controls/NavigationView/NavigationViewContentPresenter.xaml b/src/Wpf.Ui/Controls/NavigationView/NavigationViewContentPresenter.xaml index b249c26c6..cb439ea76 100644 --- a/src/Wpf.Ui/Controls/NavigationView/NavigationViewContentPresenter.xaml +++ b/src/Wpf.Ui/Controls/NavigationView/NavigationViewContentPresenter.xaml @@ -1,4 +1,4 @@ -