Improves UI structure with a shared page shell and dynamic titles

Wraps the application's content area in a stylized border and introduces a centralized, dynamic page header to provide a more cohesive look.

- Adds `Tag` attributes to navigation list items to define each view's display title
- Implements event handlers to automatically update the header text based on user navigation
- Removes redundant embedded titles from individual content pages to streamline the layouts
This commit is contained in:
rbalsleyMSFT
2026-03-23 11:52:04 -07:00
parent 002017e5e6
commit 98c1644d76
3 changed files with 812 additions and 765 deletions
+32 -18
View File
@@ -1,8 +1,6 @@
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib" Title="FFU Builder UI" xmlns:sys="clr-namespace:System;assembly=mscorlib" Title="FFU Builder UI" FontSize="14" FontFamily="Segoe UI Variable, Segoe UI" WindowState="Maximized">
FontSize="14" FontFamily="Segoe UI Variable, Segoe UI"
WindowState="Maximized">
<Grid Margin="16"> <Grid Margin="16">
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -69,7 +67,7 @@
</Setter> </Setter>
</Style> </Style>
</ListBox.ItemContainerStyle> </ListBox.ItemContainerStyle>
<ListBoxItem x:Name="navSettings" Padding="12,8" Margin="4,0"> <ListBoxItem x:Name="navSettings" Padding="12,8" Margin="4,0" Tag="Settings">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock Text="&#xE713;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/> <TextBlock Text="&#xE713;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/>
<TextBlock Text="Settings" VerticalAlignment="Center"/> <TextBlock Text="Settings" VerticalAlignment="Center"/>
@@ -115,55 +113,55 @@
</Setter> </Setter>
</Style> </Style>
</ListBox.ItemContainerStyle> </ListBox.ItemContainerStyle>
<ListBoxItem x:Name="navHome" Padding="12,8" Margin="4,0" IsSelected="True"> <ListBoxItem x:Name="navHome" Padding="12,8" Margin="4,0" IsSelected="True" Tag="Home">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock Text="&#xE80F;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/> <TextBlock Text="&#xE80F;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/>
<TextBlock Text="Home" VerticalAlignment="Center"/> <TextBlock Text="Home" VerticalAlignment="Center"/>
</StackPanel> </StackPanel>
</ListBoxItem> </ListBoxItem>
<ListBoxItem x:Name="navHyperV" Padding="12,8" Margin="4,0"> <ListBoxItem x:Name="navHyperV" Padding="12,8" Margin="4,0" Tag="Hyper-V Settings">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock Text="&#xE7F8;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/> <TextBlock Text="&#xE7F8;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/>
<TextBlock Text="Hyper-V Settings" VerticalAlignment="Center"/> <TextBlock Text="Hyper-V Settings" VerticalAlignment="Center"/>
</StackPanel> </StackPanel>
</ListBoxItem> </ListBoxItem>
<ListBoxItem x:Name="navWindows" Padding="12,8" Margin="4,0"> <ListBoxItem x:Name="navWindows" Padding="12,8" Margin="4,0" Tag="Windows Settings">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock Text="&#xE7F4;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/> <TextBlock Text="&#xE7F4;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/>
<TextBlock Text="Windows Settings" VerticalAlignment="Center"/> <TextBlock Text="Windows Settings" VerticalAlignment="Center"/>
</StackPanel> </StackPanel>
</ListBoxItem> </ListBoxItem>
<ListBoxItem x:Name="navUpdates" Padding="12,8" Margin="4,0"> <ListBoxItem x:Name="navUpdates" Padding="12,8" Margin="4,0" Tag="Updates">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock Text="&#xE895;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/> <TextBlock Text="&#xE895;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/>
<TextBlock Text="Updates" VerticalAlignment="Center"/> <TextBlock Text="Updates" VerticalAlignment="Center"/>
</StackPanel> </StackPanel>
</ListBoxItem> </ListBoxItem>
<ListBoxItem x:Name="navApplications" Padding="12,8" Margin="4,0"> <ListBoxItem x:Name="navApplications" Padding="12,8" Margin="4,0" Tag="Applications">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock Text="&#xE71D;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/> <TextBlock Text="&#xE71D;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/>
<TextBlock Text="Applications" VerticalAlignment="Center"/> <TextBlock Text="Applications" VerticalAlignment="Center"/>
</StackPanel> </StackPanel>
</ListBoxItem> </ListBoxItem>
<ListBoxItem x:Name="navOffice" Padding="12,8" Margin="4,0"> <ListBoxItem x:Name="navOffice" Padding="12,8" Margin="4,0" Tag="M365 Apps/Office">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock Text="&#xED28;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/> <TextBlock Text="&#xED28;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/>
<TextBlock Text="M365 Apps/Office" VerticalAlignment="Center"/> <TextBlock Text="M365 Apps/Office" VerticalAlignment="Center"/>
</StackPanel> </StackPanel>
</ListBoxItem> </ListBoxItem>
<ListBoxItem x:Name="navDrivers" Padding="12,8" Margin="4,0"> <ListBoxItem x:Name="navDrivers" Padding="12,8" Margin="4,0" Tag="Drivers">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock Text="&#xE964;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/> <TextBlock Text="&#xE964;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/>
<TextBlock Text="Drivers" VerticalAlignment="Center"/> <TextBlock Text="Drivers" VerticalAlignment="Center"/>
</StackPanel> </StackPanel>
</ListBoxItem> </ListBoxItem>
<ListBoxItem x:Name="navBuild" Padding="12,8" Margin="4,0"> <ListBoxItem x:Name="navBuild" Padding="12,8" Margin="4,0" Tag="Build">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock Text="&#xE943;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/> <TextBlock Text="&#xE943;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/>
<TextBlock Text="Build" VerticalAlignment="Center"/> <TextBlock Text="Build" VerticalAlignment="Center"/>
</StackPanel> </StackPanel>
</ListBoxItem> </ListBoxItem>
<ListBoxItem x:Name="navMonitor" Padding="12,8" Margin="4,0"> <ListBoxItem x:Name="navMonitor" Padding="12,8" Margin="4,0" Tag="Monitor">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock Text="&#xE7FC;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/> <TextBlock Text="&#xE7FC;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets" FontSize="16" VerticalAlignment="Center" Margin="0,0,12,0"/>
<TextBlock Text="Monitor" VerticalAlignment="Center"/> <TextBlock Text="Monitor" VerticalAlignment="Center"/>
@@ -173,7 +171,20 @@
</DockPanel> </DockPanel>
<!-- Content Area --> <!-- Content Area -->
<Grid Grid.Column="1" Margin="4,0,0,0"> <Grid Grid.Column="1" Margin="12,0,0,0">
<!-- Shared page shell -->
<Border Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}" BorderThickness="1" CornerRadius="12">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Shared page title -->
<TextBlock x:Name="txtPageTitle" Grid.Row="0" Margin="16,16,16,12" FontSize="24" FontWeight="SemiBold" Text="Home"/>
<!-- Page host -->
<Grid Grid.Row="1">
<!-- PAGE: Home --> <!-- PAGE: Home -->
<ScrollViewer x:Name="pageHome" VerticalScrollBarVisibility="Auto"> <ScrollViewer x:Name="pageHome" VerticalScrollBarVisibility="Auto">
<Grid Margin="16,0,16,16"> <Grid Margin="16,0,16,16">
@@ -716,8 +727,8 @@
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<!-- Row 0: Header --> <!-- Hidden internal header so the shared page shell owns the page title -->
<TextBlock Grid.Row="0" Text="FFU Build Settings" FontSize="20" FontWeight="SemiBold" Margin="0,0,0,8"/> <TextBlock Grid.Row="0" Text="FFU Build Settings" FontSize="20" FontWeight="SemiBold" Margin="0,0,0,8" Visibility="Collapsed"/>
<!-- Row 1: FFU Development Path --> <!-- Row 1: FFU Development Path -->
<StackPanel Grid.Row="1" Margin="0,0,0,24"> <StackPanel Grid.Row="1" Margin="0,0,0,24">
<TextBlock Text="FFU Development Path" Margin="0,0,0,4" ToolTip="Path to the FFU development folder."/> <TextBlock Text="FFU Development Path" Margin="0,0,0,4" ToolTip="Path to the FFU development folder."/>
@@ -883,8 +894,8 @@
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<!-- Settings Header --> <!-- Hidden internal header so the shared page shell owns the page title -->
<TextBlock Text="Settings" FontSize="20" FontWeight="SemiBold" Grid.Row="0" Margin="0,0,0,16"/> <TextBlock Text="Settings" FontSize="20" FontWeight="SemiBold" Grid.Row="0" Margin="0,0,0,16" Visibility="Collapsed"/>
<!-- Appearance Section --> <!-- Appearance Section -->
<StackPanel Grid.Row="1" Margin="0,0,0,24"> <StackPanel Grid.Row="1" Margin="0,0,0,24">
@@ -954,6 +965,9 @@
</ScrollViewer> </ScrollViewer>
</Grid> </Grid>
</Grid> </Grid>
</Border>
</Grid>
</Grid>
<!-- Progress Bar --> <!-- Progress Bar -->
<ProgressBar x:Name="progressBar" Height="20" Margin="0,8,0,0" Grid.Row="1" Visibility="Collapsed"/> <ProgressBar x:Name="progressBar" Height="20" Margin="0,8,0,0" Grid.Row="1" Visibility="Collapsed"/>
@@ -117,6 +117,14 @@ function Register-EventHandlers {
if ($selectedIndex -lt $localState.Controls.navigationPages.Count) { if ($selectedIndex -lt $localState.Controls.navigationPages.Count) {
$localState.Controls.navigationPages[$selectedIndex].Visibility = 'Visible' $localState.Controls.navigationPages[$selectedIndex].Visibility = 'Visible'
} }
# Update the shared page title to match the selected navigation item
if ($null -ne $localState.Controls.txtPageTitle) {
$selectedNavigationItem = $eventSource.SelectedItem
if ($null -ne $selectedNavigationItem -and -not [string]::IsNullOrWhiteSpace([string]$selectedNavigationItem.Tag)) {
$localState.Controls.txtPageTitle.Text = [string]$selectedNavigationItem.Tag
}
}
}) })
} }
@@ -145,6 +153,17 @@ function Register-EventHandlers {
if ($null -ne $localState.Controls.pageSettings) { if ($null -ne $localState.Controls.pageSettings) {
$localState.Controls.pageSettings.Visibility = 'Visible' $localState.Controls.pageSettings.Visibility = 'Visible'
} }
# Update the shared page title to match the selected navigation item
if ($null -ne $localState.Controls.txtPageTitle) {
$selectedNavigationItem = $eventSource.SelectedItem
if ($null -ne $selectedNavigationItem -and -not [string]::IsNullOrWhiteSpace([string]$selectedNavigationItem.Tag)) {
$localState.Controls.txtPageTitle.Text = [string]$selectedNavigationItem.Tag
}
else {
$localState.Controls.txtPageTitle.Text = 'Settings'
}
}
}) })
} }
@@ -280,6 +280,9 @@ function Initialize-UIControls {
# Settings page # Settings page
$State.Controls.cmbThemeMode = $window.FindName('cmbThemeMode') $State.Controls.cmbThemeMode = $window.FindName('cmbThemeMode')
# Shared page shell
$State.Controls.txtPageTitle = $window.FindName('txtPageTitle')
# Navigation controls # Navigation controls
$State.Controls.lstNavigation = $window.FindName('lstNavigation') $State.Controls.lstNavigation = $window.FindName('lstNavigation')
$State.Controls.lstNavSettings = $window.FindName('lstNavSettings') $State.Controls.lstNavSettings = $window.FindName('lstNavSettings')
@@ -473,9 +476,20 @@ function Initialize-UIDefaults {
} }
} }
# Set default navigation selection to Home and show the Home page # Set default navigation selection to Home and initialize the shared page title
if ($null -ne $State.Controls.lstNavigation) { if ($null -ne $State.Controls.lstNavigation) {
$State.Controls.lstNavigation.SelectedIndex = 0 $State.Controls.lstNavigation.SelectedIndex = 0
# Keep the shell header aligned with the selected navigation item on first render
if ($null -ne $State.Controls.txtPageTitle) {
$selectedNavigationItem = $State.Controls.lstNavigation.SelectedItem
if ($null -ne $selectedNavigationItem -and -not [string]::IsNullOrWhiteSpace([string]$selectedNavigationItem.Tag)) {
$State.Controls.txtPageTitle.Text = [string]$selectedNavigationItem.Tag
}
else {
$State.Controls.txtPageTitle.Text = 'Home'
}
}
} }
# Set initial state for Office panel visibility # Set initial state for Office panel visibility