Skip to content

Commit 8b75c39

Browse files
committed
新增自动隐藏标签栏
1 parent 70e6389 commit 8b75c39

12 files changed

+430
-57
lines changed

PreLaunchTaskr.GUI.WinUI3/App.xaml.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using PreLaunchTaskr.Core;
44
using PreLaunchTaskr.Core.Services;
55
using PreLaunchTaskr.GUI.WinUI3.ViewModels.PageModels;
6+
using PreLaunchTaskr.GUI.WinUI3.Views;
67

78
using System;
89
using System.Diagnostics;
@@ -21,12 +22,11 @@ namespace PreLaunchTaskr.GUI.WinUI3;
2122
/// </summary>
2223
public partial class App : Application
2324
{
24-
public static string DisplayVersion =>
25+
public static string DisplayVersion = "1.4.7"
2526
#if DEBUG
26-
"1.4.6 DEBUG";
27-
#else
28-
"1.4.6";
27+
+ " DEBUG"
2928
#endif
29+
;
3030

3131
/// <summary>
3232
/// Initializes the singleton application object.
@@ -59,7 +59,7 @@ public App()
5959

6060
public MainWindow MainWindow => mainWindow;
6161

62-
public MultiTabViewModel MultiTab { get; set; } = null!;
62+
public MultiTabPage MultiTab { get; set; } = null!;
6363

6464
public static string BaseDirectory { get; } = Path.GetFullPath(".");
6565

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
using Microsoft.UI.Xaml;
2+
using Microsoft.UI.Xaml.Controls;
3+
4+
using PreLaunchTaskr.GUI.WinUI3.Extensions;
5+
using PreLaunchTaskr.GUI.WinUI3.Helpers;
6+
7+
using System;
8+
using System.ComponentModel;
9+
10+
namespace PreLaunchTaskr.GUI.WinUI3.Controls;
11+
12+
public partial class TitleBarTabView : TabView
13+
{
14+
public TitleBarTabView() : base()
15+
{
16+
tabStripFooterBorder = new() { HorizontalAlignment = HorizontalAlignment.Stretch };
17+
base.TabStripFooter = tabStripFooterBorder;
18+
RegisterPropertyChangedCallback(TabView.VisibilityProperty, (o, e) => VisibilityChanged?.Invoke(this, EventArgs.Empty));
19+
}
20+
21+
public void UpdateTitleBar()
22+
{
23+
OwnerWindow?.SetTitleBar(this);
24+
titleBarPassthroughHelper?.Passthrough(this);
25+
}
26+
27+
public event EventHandler? VisibilityChanged;
28+
29+
public Window? OwnerWindow
30+
{
31+
get => (Window?) GetValue(OwnerWindowProperty);
32+
set
33+
{
34+
if (value == OwnerWindow)
35+
return;
36+
37+
SetValue(OwnerWindowProperty, value);
38+
39+
if (value is null)
40+
{
41+
titleBarPassthroughHelper = null;
42+
SizeChanged -= PassthroughTitleBarOnSizeChanged;
43+
tabStripFooterBorder.SizeChanged -= PassthroughTitleBarOnTabStripFooterSizeChanged;
44+
return;
45+
}
46+
titleBarPassthroughHelper = TitleBarPassthroughHelper.For(value);
47+
tabStripFooterBorder.MinWidth = FlowDirection switch
48+
{
49+
FlowDirection.LeftToRight => value.AppWindow.TitleBar.RightInset / XamlRoot.RasterizationScale,
50+
FlowDirection.RightToLeft => value.AppWindow.TitleBar.LeftInset / XamlRoot.RasterizationScale,
51+
_ => throw new ArgumentOutOfRangeException()
52+
};
53+
VisibilityChanged += (o, e) =>
54+
{
55+
if (Visibility == Visibility.Visible)
56+
{
57+
OwnerWindow?.SetTitleBar(this);
58+
titleBarPassthroughHelper.Passthrough(this);
59+
}
60+
};
61+
SizeChanged += PassthroughTitleBarOnSizeChanged;
62+
tabStripFooterBorder.SizeChanged += PassthroughTitleBarOnTabStripFooterSizeChanged;
63+
}
64+
}
65+
66+
public bool AutoHide
67+
{
68+
get => (bool) GetValue(AutoHideProperty);
69+
set
70+
{
71+
SetValue(AutoHideProperty, value);
72+
73+
if (value)
74+
{
75+
TabItemsChanged += ShowOrHideOnTabItemsChanged;
76+
}
77+
else
78+
{
79+
TabItemsChanged -= ShowOrHideOnTabItemsChanged;
80+
}
81+
}
82+
}
83+
84+
public new UIElement? TabStripFooter
85+
{
86+
get => (UIElement?) GetValue(TabStripFooterProperty);
87+
set => SetValue(TabStripFooterProperty, value);
88+
}
89+
90+
public Action<FrameworkElement>? PassthroughAlternativeTitleBar;
91+
92+
public static readonly DependencyProperty OwnerWindowProperty = DependencyProperty.Register
93+
(
94+
nameof(OwnerWindow),
95+
typeof(Window),
96+
typeof(TitleBarTabView),
97+
new PropertyMetadata(default(Window))
98+
);
99+
100+
public static readonly DependencyProperty AutoHideProperty = DependencyProperty.Register
101+
(
102+
nameof(AutoHide),
103+
typeof(bool),
104+
typeof(TitleBarTabView),
105+
new PropertyMetadata(false)
106+
);
107+
108+
public static new readonly DependencyProperty TabStripFooterProperty = DependencyProperty.Register
109+
(
110+
nameof(TabStripFooter),
111+
typeof(UIElement),
112+
typeof(TitleBarTabView),
113+
new PropertyMetadata(default, (d, e) =>
114+
{
115+
TitleBarTabView self = (TitleBarTabView) d;
116+
self.tabStripFooterBorder.Child = (UIElement) e.NewValue;
117+
})
118+
);
119+
120+
protected readonly Border tabStripFooterBorder;
121+
122+
private TitleBarPassthroughHelper? titleBarPassthroughHelper;
123+
124+
private bool isSizeChanged; // SizeChanged ·¢ÉúÏÈÓÚ×ÓÔªËØ
125+
126+
private void ShowOrHideOnTabItemsChanged(TabView sender, Windows.Foundation.Collections.IVectorChangedEventArgs args)
127+
{
128+
sender.Visibility = sender.TabItems.Count > 1 ? Visibility.Visible : Visibility.Collapsed;
129+
}
130+
131+
private void PassthroughTitleBarOnTabStripFooterSizeChanged(object sender, SizeChangedEventArgs e)
132+
{
133+
if (!isSizeChanged)
134+
{
135+
OwnerWindow?.SetTitleBar(this);
136+
titleBarPassthroughHelper?.Passthrough(this);
137+
}
138+
isSizeChanged = false;
139+
}
140+
141+
private void PassthroughTitleBarOnSizeChanged(object sender, SizeChangedEventArgs e)
142+
{
143+
isSizeChanged = true;
144+
OwnerWindow?.SetTitleBar(this);
145+
titleBarPassthroughHelper?.Passthrough(this);
146+
}
147+
}

PreLaunchTaskr.GUI.WinUI3/Helpers/TitleBarPassthroughHelper.cs

Lines changed: 52 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,23 @@ namespace PreLaunchTaskr.GUI.WinUI3.Helpers;
1111

1212
public class TitleBarPassthroughHelper
1313
{
14-
public TitleBarPassthroughHelper(Window window)
14+
public static TitleBarPassthroughHelper For(Window window)
15+
{
16+
if (!cacheForWindow.TryGetValue(window, out TitleBarPassthroughHelper? instance))
17+
{
18+
instance = new TitleBarPassthroughHelper(window);
19+
cacheForWindow.Add(window, instance);
20+
}
21+
return instance;
22+
}
23+
24+
private static readonly Dictionary<Window, TitleBarPassthroughHelper> cacheForWindow = new();
25+
26+
private TitleBarPassthroughHelper(Window window)
1527
{
1628
this.window = window;
1729
// System.Runtime.InteropServices.COMException
18-
// The WinUI Desktop Window object has already been closed.
30+
// The WinUI Desktop Window object has already been closed.
1931
// this.scale = window.Content.XamlRoot.RasterizationScale;
2032
}
2133

@@ -24,39 +36,38 @@ public TitleBarPassthroughHelper(Window window)
2436

2537
public void Passthrough(TabView tabView)
2638
{
27-
this.scale = window.Content.XamlRoot.RasterizationScale;
28-
if (tabView.TabItems.Count > 0)
39+
if (tabView.TabItems.Count == 0)
40+
return;
41+
42+
scale = window.Content.XamlRoot.RasterizationScale;
43+
double passthroughWidth = 0.0;
44+
for (int i = 0; i < tabView.TabItems.Count; i++)
45+
{
46+
FrameworkElement? tab = (FrameworkElement) tabView.ContainerFromIndex(i) ?? tabView.TabItems[0] as FrameworkElement;
47+
if (tab is null)
48+
continue;
49+
passthroughWidth += tab.ActualWidth;
50+
}
51+
if (passthroughWidth == 0.0)
52+
return;
53+
if (tabView.IsAddTabButtonVisible)
2954
{
30-
scale = window.Content.XamlRoot.RasterizationScale;
31-
double passthroughWidth = 0.0;
32-
//double passthroughHeight = 0.0;
33-
for (int i = 0; i < tabView.TabItems.Count; i++)
34-
{
35-
FrameworkElement tab = (FrameworkElement) tabView.ContainerFromIndex(i);
36-
if (tab is null)
37-
continue;
38-
passthroughWidth += tab.ActualWidth;
39-
//passthroughHeight = tab.ActualHeight;
40-
}
41-
if (tabView.IsAddTabButtonVisible)
42-
{
43-
passthroughWidth = passthroughWidth
44-
+ (double) Application.Current.Resources["TabViewItemAddButtonWidth"]
45-
+ ((Thickness) Application.Current.Resources["TabViewItemAddButtonContainerPadding"]).Left
46-
+ ((Thickness) Application.Current.Resources["TabViewItemAddButtonContainerPadding"]).Right;
47-
}
48-
FrameworkElement firstTab = (FrameworkElement) tabView.ContainerFromIndex(0);
49-
Point position = firstTab.TransformToVisual(window.Content).TransformPoint(new());
50-
Rect rect = tabView.TransformToVisual(null).TransformBounds(new Rect(
51-
x: position.X,
52-
y: position.Y,
53-
width: passthroughWidth,
54-
height: firstTab.ActualHeight
55-
));
56-
InputNonClientPointerSource
57-
.GetForWindowId(window.AppWindow.Id)
58-
.SetRegionRects(NonClientRegionKind.Passthrough, [GetPixelRectInt32(rect, scale)]);
55+
passthroughWidth = passthroughWidth
56+
+ (double) Application.Current.Resources["TabViewItemAddButtonWidth"]
57+
+ ((Thickness) Application.Current.Resources["TabViewItemAddButtonContainerPadding"]).Left
58+
+ ((Thickness) Application.Current.Resources["TabViewItemAddButtonContainerPadding"]).Right;
5959
}
60+
FrameworkElement firstTab = (FrameworkElement) tabView.ContainerFromIndex(0);
61+
Point position = firstTab.TransformToVisual(window.Content).TransformPoint(new());
62+
Rect rect = tabView.TransformToVisual(null).TransformBounds(new Rect(
63+
x: position.X,
64+
y: position.Y,
65+
width: passthroughWidth,
66+
height: firstTab.ActualHeight
67+
));
68+
InputNonClientPointerSource
69+
.GetForWindowId(window.AppWindow.Id)
70+
.SetRegionRects(NonClientRegionKind.Passthrough, [GetPixelRectInt32(rect, scale)]);
6071
}
6172

6273
public void Passthrough(FrameworkElement element)
@@ -69,7 +80,7 @@ public void Passthrough(FrameworkElement element)
6980

7081
public void Passthrough(IList<FrameworkElement> elements)
7182
{
72-
this.scale = window.Content.XamlRoot.RasterizationScale;
83+
scale = window.Content.XamlRoot.RasterizationScale;
7384
RectInt32[] rects = new RectInt32[elements.Count];
7485
int count = 0;
7586
foreach (var element in elements)
@@ -82,6 +93,13 @@ public void Passthrough(IList<FrameworkElement> elements)
8293
.SetRegionRects(NonClientRegionKind.Passthrough, rects);
8394
}
8495

96+
public void ResetPassthrough()
97+
{
98+
InputNonClientPointerSource
99+
.GetForWindowId(window.AppWindow.Id)
100+
.ClearRegionRects(NonClientRegionKind.Passthrough);
101+
}
102+
85103
private RectInt32 GetUIElementPixelRectInt32(FrameworkElement element)
86104
{
87105
Point dipPosition = element.TransformToVisual(window.Content).TransformPoint(new Point());

PreLaunchTaskr.GUI.WinUI3/MainWindow.xaml.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ public sealed partial class MainWindow : Window
2525
{
2626
public MainWindow()
2727
{
28+
//ContentDialogWindow window = new();
29+
//window.Activate();
2830
InitializeComponent();
2931
ExtendsContentIntoTitleBar = true;
3032
AppWindow.TitleBar.ButtonHoverBackgroundColor = Color.FromArgb(32, 128, 128, 128);

PreLaunchTaskr.GUI.WinUI3/PreLaunchTaskr.GUI.WinUI3.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<None Remove="Views\AttachArgumentPage.xaml" />
3232
<None Remove="Views\BannerPage.xaml" />
3333
<None Remove="Views\BlockArgumentPage.xaml" />
34+
<None Remove="Views\ContentDialogWindow.xaml" />
3435
<None Remove="Views\EnvironmentVariablePage.xaml" />
3536
<None Remove="Views\InstalledPackagedProgramListPage.xaml" />
3637
<None Remove="Views\InstalledProgramListPage.xaml" />
@@ -100,6 +101,9 @@
100101
<None Update="readme.txt">
101102
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
102103
</None>
104+
<Page Update="Views\ContentDialogWindow.xaml">
105+
<Generator>MSBuild:Compile</Generator>
106+
</Page>
103107
<Page Update="Views\BannerPage.xaml">
104108
<Generator>MSBuild:Compile</Generator>
105109
</Page>

PreLaunchTaskr.GUI.WinUI3/PreLaunchTaskr.GUI.WinUI3.csproj.user

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
<None Update="App.xaml">
1111
<SubType>Designer</SubType>
1212
</None>
13+
<Page Update="Views\ContentDialogWindow.xaml">
14+
<SubType>Designer</SubType>
15+
</Page>
1316
<Page Update="Views\BannerPage.xaml">
1417
<SubType>Designer</SubType>
1518
</Page>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<Window
3+
x:Class="PreLaunchTaskr.GUI.WinUI3.Views.ContentDialogWindow"
4+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
5+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
6+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7+
xmlns:local="using:PreLaunchTaskr.GUI.WinUI3.Views"
8+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
9+
Title="ContentDialogWindow"
10+
mc:Ignorable="d">
11+
12+
<Window.SystemBackdrop>
13+
<MicaBackdrop />
14+
</Window.SystemBackdrop>
15+
16+
<Grid>
17+
<Grid.RowDefinitions>
18+
<RowDefinition Height="*" />
19+
<RowDefinition Height="auto" />
20+
</Grid.RowDefinitions>
21+
22+
<Grid Grid.Row="0" Margin="24">
23+
<Grid.RowDefinitions>
24+
<RowDefinition Height="*" />
25+
<RowDefinition Height="auto" />
26+
</Grid.RowDefinitions>
27+
28+
<TextBlock
29+
Grid.Row="0"
30+
Style="{ThemeResource SubtitleTextBlockStyle}"
31+
Text="{x:Bind Title}" />
32+
33+
<ContentPresenter Grid.Row="1" Content="{x:Bind Content}" />
34+
</Grid>
35+
36+
<Grid Grid.Row="1" Background="{ThemeResource ContentDialogBackground}">
37+
<StackPanel Orientation="Horizontal">
38+
<Button Content="OK" />
39+
</StackPanel>
40+
</Grid>
41+
</Grid>
42+
</Window>

0 commit comments

Comments
 (0)