Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<PackageVersion Include="ReflectionEventing.DependencyInjection" Version="3.1.0" />
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
<PackageVersion Include="System.Drawing.Common" Version="9.0.1" />
<PackageVersion Include="System.Text.Json" Version="9.0.1" />
<PackageVersion Include="System.ValueTuple" Version="4.5.0" />
<PackageVersion Include="WpfAnalyzers" Version="4.1.1" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.1" />
Expand Down
28 changes: 28 additions & 0 deletions src/Wpf.Ui.Gallery/Models/AppConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 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.Models;

/// <summary>
/// Application configuration model.
/// </summary>
public class AppConfig
{
/// <summary>
/// Gets or sets the configurations folder.
/// </summary>
public string? ConfigurationsFolder { get; set; }

/// <summary>
/// Gets or sets the app properties file name.
/// </summary>
public string? AppPropertiesFileName { get; set; }

/// <summary>
/// Gets or sets the navigation pane width.
/// </summary>
public double NavigationPaneWidth { get; set; } = 310.0;
}

75 changes: 75 additions & 0 deletions src/Wpf.Ui.Gallery/Services/AppConfigService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// 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.Text.Json;
using Wpf.Ui.Gallery.Models;

namespace Wpf.Ui.Gallery.Services;

/// <summary>
/// Application configuration service.
/// </summary>
public class AppConfigService
{
private readonly string _configFilePath;
private readonly AppConfig _config;

public AppConfigService()
{
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string appFolder = Path.Combine(appDataPath, "Wpf.Ui.Gallery");

if (!Directory.Exists(appFolder))
{
_ = Directory.CreateDirectory(appFolder);
}

_configFilePath = Path.Combine(appFolder, "config.json");
_config = LoadConfig();
}

public AppConfig Config => _config;

private AppConfig LoadConfig()
{
if (File.Exists(_configFilePath))
{
try
{
string json = File.ReadAllText(_configFilePath);
return JsonSerializer.Deserialize<AppConfig>(json) ?? new AppConfig();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Error loading config: {ex.Message}");
return new AppConfig();
}
}
return new AppConfig();
}

private void SaveConfig(AppConfig config)
{
try
{
string json = JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(_configFilePath, json);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Error saving config: {ex.Message}");
}
}

/// <summary>
/// Updates the navigation pane width and saves the configuration
/// </summary>
/// <param name="newWidth">The new width value</param>
public void UpdateNavigationPaneWidth(double newWidth)
{
_config.NavigationPaneWidth = newWidth;
SaveConfig(_config);
}
}
30 changes: 28 additions & 2 deletions src/Wpf.Ui.Gallery/Views/Windows/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
BreadcrumbBar="{Binding ElementName=BreadcrumbBar}"
EnableDebugMessages="True"
FooterMenuItemsSource="{Binding ViewModel.FooterMenuItems, Mode=OneWay}"
FrameMargin="0"
FrameMargin="0,100"
IsBackButtonVisible="Visible"
IsPaneToggleVisible="True"
MenuItemsSource="{Binding ViewModel.MenuItems, Mode=OneWay}"
Expand All @@ -50,11 +50,37 @@
PaneOpened="NavigationView_OnPaneOpened"
SelectionChanged="OnNavigationSelectionChanged"
TitleBar="{Binding ElementName=TitleBar, Mode=OneWay}"
Transition="FadeInWithSlide">
Transition="FadeInWithSlide"
IsPaneResizable="True"
PaneResizeMinWidth="200"
PaneResizeMaxWidth="500">
<ui:NavigationView.Header>
<StackPanel Margin="42,32,42,20">
<ui:BreadcrumbBar x:Name="BreadcrumbBar" />
<controls:PageControlDocumentation Margin="0,10,0,0" NavigationView="{Binding ElementName=NavigationView}" />

<!-- Slider for changing navigation bar width -->
<StackPanel Margin="0,20,0,0" Orientation="Horizontal">
<TextBlock Text="Navigation Bar Width:" VerticalAlignment="Center" Margin="0,0,10,0" />
<Slider
x:Name="PaneWidthSlider"
Width="150"
Minimum="200"
Maximum="500"
Value="310"
TickFrequency="10"
ValueChanged="PaneWidthSlider_ValueChanged" />
<TextBlock Text="{Binding ElementName=NavigationView, Path=OpenPaneLength, StringFormat='{}{0:0}px'}" VerticalAlignment="Center" Margin="10,0,0,0" />
</StackPanel>
<!-- Display of resize functionality status -->
<StackPanel Margin="0,10,0,0" Orientation="Horizontal">
<TextBlock Text="Resizable:" VerticalAlignment="Center" Margin="0,0,10,0" />
<CheckBox IsChecked="{Binding ElementName=NavigationView, Path=IsPaneResizable}" VerticalAlignment="Center" />
<TextBlock Text="Min Width:" VerticalAlignment="Center" Margin="20,0,10,0" />
<TextBlock Text="{Binding ElementName=NavigationView, Path=PaneResizeMinWidth}" VerticalAlignment="Center" />
<TextBlock Text="Max Width:" VerticalAlignment="Center" Margin="20,0,10,0" />
<TextBlock Text="{Binding ElementName=NavigationView, Path=PaneResizeMaxWidth}" VerticalAlignment="Center" />
</StackPanel>
</StackPanel>
</ui:NavigationView.Header>
<ui:NavigationView.AutoSuggestBox>
Expand Down
42 changes: 40 additions & 2 deletions src/Wpf.Ui.Gallery/Views/Windows/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// All Rights Reserved.

using Wpf.Ui.Controls;
using Wpf.Ui.Gallery.Services;
using Wpf.Ui.Gallery.Services.Contracts;
using Wpf.Ui.Gallery.ViewModels.Windows;
using Wpf.Ui.Gallery.Views.Pages;
Expand All @@ -12,6 +13,8 @@ namespace Wpf.Ui.Gallery.Views.Windows;

public partial class MainWindow : IWindow
{
private readonly AppConfigService _configService;

public MainWindow(
MainWindowViewModel viewModel,
INavigationService navigationService,
Expand All @@ -25,11 +28,21 @@ IContentDialogService contentDialogService
ViewModel = viewModel;
DataContext = this;

// Initialize configuration service
_configService = new AppConfigService();

InitializeComponent();

// Restore saved navigation pane width
RestoreNavigationPaneWidth();

SetPageService(serviceProvider.GetService<IPageService>()!);
snackbarService.SetSnackbarPresenter(SnackbarPresenter);
navigationService.SetNavigationControl(NavigationView);
contentDialogService.SetDialogHost(RootContentDialog);
contentDialogService.Set = RootContentDialog;

NavigationView.Set
NavigationView.SetCurrentValue(NavigationView.MenuItemsSourceProperty, ViewModel.MenuItems);
NavigationView.SetCurrentValue(NavigationView.FooterMenuItemsSourceProperty, ViewModel.FooterMenuItems);
}

public MainWindowViewModel ViewModel { get; }
Expand All @@ -38,6 +51,31 @@ IContentDialogService contentDialogService

private bool _isPaneOpenedOrClosedFromCode;

/// <summary>
/// Handles the value change event of the navigation pane width slider
/// </summary>
private void PaneWidthSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (NavigationView != null && e.NewValue > 0)
{
NavigationView.SetCurrentValue(NavigationView.OpenPaneLengthProperty, e.NewValue);
_configService.UpdateNavigationPaneWidth(e.NewValue);
}
}

/// <summary>
/// Restores the saved navigation pane width
/// </summary>
private void RestoreNavigationPaneWidth()
{
var savedWidth = _configService.Config.NavigationPaneWidth;
if (savedWidth >= 200 && savedWidth <= 500)
{
NavigationView.SetCurrentValue(NavigationView.OpenPaneLengthProperty, savedWidth);
PaneWidthSlider.SetCurrentValue(System.Windows.Controls.Primitives.RangeBase.ValueProperty, savedWidth);
}
}

private void OnNavigationSelectionChanged(object sender, RoutedEventArgs e)
{
if (sender is not Wpf.Ui.Controls.NavigationView navigationView)
Expand Down
1 change: 1 addition & 0 deletions src/Wpf.Ui.Gallery/Wpf.Ui.Gallery.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<PackageReference Include="Microsoft.Web.WebView2" />
<PackageReference Include="ReflectionEventing" />
<PackageReference Include="ReflectionEventing.DependencyInjection" />
<PackageReference Include="System.Text.Json" />
</ItemGroup>

<ItemGroup>
Expand Down
51 changes: 51 additions & 0 deletions src/Wpf.Ui/Controls/NavigationView/NavigationView.Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,30 @@ public partial class NavigationView
new FrameworkPropertyMetadata(default(Thickness))
);

/// <summary>Identifies the <see cref="IsPaneResizable"/> dependency property.</summary>
public static readonly DependencyProperty IsPaneResizableProperty = DependencyProperty.Register(
nameof(IsPaneResizable),
typeof(bool),
typeof(NavigationView),
new FrameworkPropertyMetadata(true)
);

/// <summary>Identifies the <see cref="PaneResizeMinWidth"/> dependency property.</summary>
public static readonly DependencyProperty PaneResizeMinWidthProperty = DependencyProperty.Register(
nameof(PaneResizeMinWidth),
typeof(double),
typeof(NavigationView),
new FrameworkPropertyMetadata(200.0)
);

/// <summary>Identifies the <see cref="PaneResizeMaxWidth"/> dependency property.</summary>
public static readonly DependencyProperty PaneResizeMaxWidthProperty = DependencyProperty.Register(
nameof(PaneResizeMaxWidth),
typeof(double),
typeof(NavigationView),
new FrameworkPropertyMetadata(500.0)
);

/// <summary>
/// Gets or sets a value indicating whether debugging messages for this control are enabled
/// </summary>
Expand Down Expand Up @@ -450,6 +474,33 @@ public Thickness FrameMargin
set => SetValue(FrameMarginProperty, value);
}

/// <summary>
/// Gets or sets a value indicating whether the navigation pane is resizable.
/// </summary>
public bool IsPaneResizable
{
get => (bool)GetValue(IsPaneResizableProperty);
set => SetValue(IsPaneResizableProperty, value);
}

/// <summary>
/// Gets or sets the minimum width for resizing the navigation pane.
/// </summary>
public double PaneResizeMinWidth
{
get => (double)GetValue(PaneResizeMinWidthProperty);
set => SetValue(PaneResizeMinWidthProperty, value);
}

/// <summary>
/// Gets or sets the maximum width for resizing the navigation pane.
/// </summary>
public double PaneResizeMaxWidth
{
get => (double)GetValue(PaneResizeMaxWidthProperty);
set => SetValue(PaneResizeMaxWidthProperty, value);
}

private void OnMenuItemsSource_CollectionChanged(
object? sender,
IList collection,
Expand Down
11 changes: 11 additions & 0 deletions src/Wpf.Ui/Controls/NavigationView/NavigationViewCompact.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<ResourceDictionary Source="pack://application:,,,/Wpf.Ui;component/Controls/NavigationView/NavigationViewBasePaneButtonStyle.xaml" />
<ResourceDictionary Source="pack://application:,,,/Wpf.Ui;component/Controls/NavigationView/NavigationViewItemDefaultStyle.xaml" />
<ResourceDictionary Source="pack://application:,,,/Wpf.Ui;component/Controls/NavigationView/NavigationViewConstants.xaml" />
<ResourceDictionary Source="pack://application:,,,/Wpf.Ui;component/Controls/NavigationView/NavigationViewResizeHandle.xaml" />
</ResourceDictionary.MergedDictionaries>

<ControlTemplate x:Key="LeftCompactNavigationViewItemTemplate" TargetType="{x:Type controls:NavigationViewItem}">
Expand Down Expand Up @@ -421,6 +422,16 @@
</Grid>
</Grid>
</Border>

<!-- Resize handle -->
<controls:NavigationViewResizeHandle
x:Name="PART_ResizeHandle"
HorizontalAlignment="Right"
VerticalAlignment="Stretch"
MinWidth="{TemplateBinding PaneResizeMinWidth}"
MaxWidth="{TemplateBinding PaneResizeMaxWidth}"
CurrentWidth="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=OpenPaneLength, Mode=TwoWay}"
Visibility="{TemplateBinding IsPaneResizable, Converter={StaticResource BoolToVisibilityConverter}}" />
</Grid>

<Border
Expand Down
Loading