文件上传页面

This commit is contained in:
wenyongda 2025-06-17 17:33:31 +08:00
parent 6efda290ca
commit de0a0e3e78
21 changed files with 783 additions and 8 deletions

View File

@ -0,0 +1,54 @@
syntax = "proto3";
option csharp_namespace = "WinUINotes.Grpc";
package filetransfer;
service FileTransfer {
rpc InitUpload (InitUploadRequest) returns (InitUploadResponse);
rpc UploadChunk (stream UploadChunkRequest) returns (UploadChunkResponse);
rpc CompleteUpload (CompleteUploadRequest) returns (CompleteUploadResponse);
rpc CheckUploadStatus (CheckUploadStatusRequest) returns (CheckUploadStatusResponse);
}
message InitUploadRequest {
string file_name = 1;
int64 file_size = 2;
string file_hash = 3;
}
message InitUploadResponse {
string session_id = 1;
int64 uploaded_bytes = 2;
}
message UploadChunkRequest {
string session_id = 1;
bytes chunk_data = 2;
int64 offset = 3;
}
message UploadChunkResponse {
int64 uploaded_bytes = 1;
}
message CompleteUploadRequest {
string session_id = 1;
string file_hash = 2;
}
message CompleteUploadResponse {
bool success = 1;
string message = 2;
}
message CheckUploadStatusRequest {
string file_name = 1;
string file_hash = 2;
}
message CheckUploadStatusResponse {
string session_id = 1;
int64 uploaded_bytes = 2;
bool exists = 3;
}

View File

@ -1,6 +1,6 @@
syntax = "proto3";
option csharp_namespace = "WinUINotes";
option csharp_namespace = "WinUINotes.Grpc";
package greet;

View File

@ -1,6 +1,6 @@
syntax = "proto3";
option csharp_namespace = "ZR.Admin.Grpc";
option csharp_namespace = "WinUINotes.Grpc";
package my.diary;

View File

@ -20,5 +20,6 @@
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
<Protobuf Include="Protos\my_diary.proto" GrpcServices="Client" />
<Protobuf Include="Protos\FileTransfer.proto" GrpcServices="Client" />
</ItemGroup>
</Project>

14
WinUINotes/AboutPage.xaml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Page
x:Class="WinUINotes.AboutPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WinUINotes"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<TextBlock Text="这是关于页面。" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Page>

View File

@ -0,0 +1,31 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace WinUINotes
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class AboutPage : Page
{
public AboutPage()
{
InitializeComponent();
}
}
}

View File

@ -26,7 +26,9 @@ namespace WinUINotes
/// </summary>
public partial class App : Application
{
private Window? _window;
private static Window? _window;
public static Window m_window => _window;
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code

View File

@ -0,0 +1,73 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
namespace WinUINotes.Common
{
public static class FileHelper
{
// 最佳缓冲区大小经过测试得出(根据硬件调整)
private const int OptimalBufferSize = 1 * 1024 * 1024; // 1MB缓冲区
public static string CalculateFileHash(string filePath)
{
using (var md5 = MD5.Create())
using (var stream = File.OpenRead(filePath))
{
var hash = md5.ComputeHash(stream);
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
}
//public static async Task<string> CalculateFileHashAsync(string filePath)
//{
// using (var md5 = MD5.Create())
// using (var stream = File.OpenRead(filePath))
// {
// var hash = await md5.ComputeHashAsync(stream);
// return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
// }
//}
public static async Task<string> CalculateFileHashAsync(string filePath, int bufferSize = 81920 /* 默认缓冲区大小 */, CancellationToken cancellationToken = default)
{
using (var md5 = MD5.Create())
{
// 使用带有异步选项和优化缓冲区大小的FileStream
using (var stream = new FileStream(
filePath,
FileMode.Open,
FileAccess.Read,
FileShare.Read,
bufferSize: bufferSize,
options: FileOptions.SequentialScan | FileOptions.Asynchronous))
{
var hash = await md5.ComputeHashAsync(stream, cancellationToken)
.ConfigureAwait(false);
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
}
}
// 快速文件标识前1MB哈希 + 文件大小)
public static async Task<string> GetQuickFileIdentity(string filePath)
{
const int sampleSize = 1 * 1024 * 1024; // 1MB
var fileInfo = new FileInfo(filePath);
long fileSize = fileInfo.Length;
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[Math.Min(sampleSize, fileSize)];
int bytesRead = await fs.ReadAsync(buffer, 0, buffer.Length);
using (var sha = SHA256.Create())
{
byte[] hashBytes = sha.ComputeHash(buffer);
return $"{fileSize}-{BitConverter.ToString(hashBytes).Replace("-", "")}";
}
}
}
}
}

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<Page
x:Class="WinUINotes.FileUploadPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WinUINotes"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Margin="12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Border Grid.Row="0" BorderBrush="LightGray" BorderThickness="1" CornerRadius="4" Padding="10" Margin="0,0,0,10">
<StackPanel>
<TextBlock Text="文件信息" FontWeight="SemiBold" Margin="0,0,0,10">
</TextBlock>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox x:Name="txtFilePath" IsReadOnly="True" PlaceholderText="文件路径" Grid.Column="0" VerticalAlignment="Center"></TextBox>
<Button x:Name="btnBrowse" Content="浏览" Grid.Column="1" Margin="10,0,0,0" Click="BtnBrowse_OnClick"/>
</Grid>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<Button x:Name="btnUpload" Content="上传" Click="BtnUpload_OnClick" Margin="0,0,10,0"/>
<Button x:Name="btnPause" Content="暂停" IsEnabled="False" Click="BtnPause_OnClick" Margin="0,0,10,0"/>
<Button x:Name="btnCancel" Content="取消" IsEnabled="False" Click="BtnCancel_OnClick"/>
</StackPanel>
<TextBlock x:Name="lblFileSize" Text="大小: -" Margin="0,10,0,0"/>
</StackPanel>
</Border>
<Border Grid.Row="1" BorderBrush="LightGray" BorderThickness="1" CornerRadius="4" Padding="10">
<StackPanel>
<TextBlock Text="上传进度" FontWeight="SemiBold" Margin="0,0,0,10"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ProgressBar x:Name="progressBar" Grid.Column="0" Minimum="0" Maximum="100"/>
<TextBlock x:Name="lblPercentage" Text="0%" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="10,0,0,0"/>
</Grid>
<TextBlock x:Name="lblProgress" Margin="0,5,0,0"/>
</StackPanel>
</Border>
</Grid>
</Page>

View File

@ -0,0 +1,347 @@
using Grpc.Core;
using Grpc.Net.Client;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Media.Protection.PlayReady;
using Windows.Storage;
using Windows.Storage.Pickers;
using WinRT.Interop;
using WinUINotes.Common;
using WinUINotes.Grpc;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace WinUINotes
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class FileUploadPage : Page
{
private GrpcChannel _channel;
private FileTransfer.FileTransferClient _client;
private CancellationTokenSource _cancellationTokenSource;
public FileUploadPage()
{
InitializeComponent();
InitializeGrpcClient();
}
private async void InitializeGrpcClient()
{
try
{
// 注意: 对于生产环境,应该使用更安全的通道配置
_channel = GrpcChannel.ForAddress("http://localhost:5065");
_client = new FileTransfer.FileTransferClient(_channel);
}
catch (Exception ex)
{
//var errorDialog = new ContentDialog
//{
// Title = "Error",
// Content = $"初始化gRPC客户端失败: {ex.Message}",
// CloseButtonText = "确定", // Equivalent to MessageBoxButtons.OK
// // For XamlRoot, assume 'this' refers to your current Window or Page
// XamlRoot = this.Content.XamlRoot
//};
//await errorDialog.ShowAsync();
await ShowErrorDialog($"初始化gRPC客户端失败: {ex.Message}", "Error");
}
}
private async void BtnBrowse_OnClick(object sender, RoutedEventArgs e)
{
//disable the button to avoid double-clicking
var senderButton = sender as Button;
senderButton.IsEnabled = false;
var picker = new FileOpenPicker();
// IMPORTANT: For desktop WinUI 3 apps, you must associate the picker with the window.
// Get the current window's HWND (handle). 'this' should refer to your MainWindow or Page.
var hwnd = WindowNative.GetWindowHandle(App.m_window);
InitializeWithWindow.Initialize(picker, hwnd);
// Set properties similar to OpenFileDialog
picker.ViewMode = PickerViewMode.Thumbnail; // Or List, Details
//picker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary; // Or Desktop, PicturesLibrary, etc.
// Add file type filters. For all files, use "*"
picker.FileTypeFilter.Add("*");
// Example for specific types:
// picker.FileTypeFilter.Add(".txt");
// picker.FileTypeFilter.Add(".docx");
// Since Multiselect = false in original, use PickSingleFileAsync()
StorageFile file = await picker.PickSingleFileAsync();
if (file != null)
{
// 'file' is a StorageFile object, not just a path string.
txtFilePath.Text = file.Path;
// Get file size using StorageFile's properties (more UWP/WinUI friendly)
var properties = await file.GetBasicPropertiesAsync();
lblFileSize.Text = $"大小: {FormatFileSize(properties.Size)}"; // Assuming FormatFileSize can handle ulong
// Reset progress display
progressBar.Value = 0;
lblProgress.Text = ""; // Or "文件已选择。"
lblPercentage.Text = "0%";
// Store the selected file if you need to use it later for upload
// e.g., _selectedFile = file; (where _selectedFile is a StorageFile field)
btnUpload.IsEnabled = true; // Enable the upload button if you have one
lblProgress.Text = "文件已选择。";
}
else
{
// User canceled the file selection
txtFilePath.Text = string.Empty;
lblFileSize.Text = "大小: -";
btnUpload.IsEnabled = false; // Disable upload if no file is selected
lblProgress.Text = "未选择文件。";
progressBar.Value = 0;
lblPercentage.Text = "0%";
}
senderButton.IsEnabled = true;
}
private async void BtnUpload_OnClick(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(txtFilePath.Text) || !File.Exists(txtFilePath.Text))
{
await ShowErrorDialog("请选择一个有效文件.", "Error");
return;
}
var filePath = txtFilePath.Text;
var fileInfo = new FileInfo(filePath);
if (fileInfo.Length > 100L * 1024 * 1024 * 1024) // 100GB
{
await ShowErrorDialog("文件大小限制为100GB.", "Error");
return;
}
// 禁用UI控件
SetUploadControls(false);
_cancellationTokenSource = new CancellationTokenSource();
try
{
await UploadFileWithResume(filePath, _cancellationTokenSource.Token);
await ShowInfoDialog("文件上传成功!", "Success");
}
catch (OperationCanceledException)
{
await ShowInfoDialog("上传取消.", "Info");
}
catch (RpcException rpcEx) when (rpcEx.StatusCode == StatusCode.Unavailable)
{
await ShowErrorDialog("服务无效,请检查连接.", "Error");
}
catch (Exception ex)
{
await ShowErrorDialog($"上传失败: {ex.Message}", "Error");
}
finally
{
// 重新启用UI控件
SetUploadControls(true);
}
}
private void SetUploadControls(bool enable)
{
btnBrowse.IsEnabled = enable;
btnUpload.IsEnabled = enable;
btnPause.IsEnabled = !enable;
btnCancel.IsEnabled = !enable;
}
private async Task UploadFileWithResume(string filePath, CancellationToken cancellationToken)
{
var fileInfo = new FileInfo(filePath);
var fileHash = await FileHelper.GetQuickFileIdentity(filePath);
const int chunkSize = 10 * 1024 * 1024; // 1MB chunk size
// 检查服务器上是否已有上传记录
var statusResponse = await _client.CheckUploadStatusAsync(new CheckUploadStatusRequest
{
FileName = fileInfo.Name,
FileHash = fileHash
});
string sessionId;
ulong uploadedBytes = 0;
if (statusResponse.Exists && statusResponse.UploadedBytes > 0)
{
// 恢复已有上传
sessionId = statusResponse.SessionId;
uploadedBytes = (ulong)statusResponse.UploadedBytes;
}
else
{
// 开始新上传
var initResponse = await _client.InitUploadAsync(new InitUploadRequest
{
FileName = fileInfo.Name,
FileSize = fileInfo.Length,
FileHash = fileHash
});
sessionId = initResponse.SessionId;
uploadedBytes = (ulong)initResponse.UploadedBytes;
}
// 更新UI显示初始进度
UpdateProgress(uploadedBytes, (ulong)fileInfo.Length);
// 打开文件准备读取
using (var fileStream = File.OpenRead(filePath))
{
fileStream.Seek((long)uploadedBytes, SeekOrigin.Begin);
var call = _client.UploadChunk();
var remainingBytes = fileInfo.Length - (long)uploadedBytes;
while (remainingBytes > 0 && !cancellationToken.IsCancellationRequested)
{
var currentChunkSize = (int)Math.Min(chunkSize, remainingBytes);
var buffer = new byte[currentChunkSize];
var bytesRead = await fileStream.ReadAsync(buffer, 0, currentChunkSize, cancellationToken);
if (bytesRead == 0) break;
await call.RequestStream.WriteAsync(new UploadChunkRequest
{
SessionId = sessionId,
ChunkData = Google.Protobuf.ByteString.CopyFrom(buffer),
Offset = (long)uploadedBytes
});
uploadedBytes += (ulong)bytesRead;
remainingBytes -= bytesRead;
// 更新UI进度
UpdateProgress(uploadedBytes, (ulong)fileInfo.Length);
}
await call.RequestStream.CompleteAsync();
var response = await call.ResponseAsync;
}
if (!cancellationToken.IsCancellationRequested)
{
// 完成上传
var completeResponse = await _client.CompleteUploadAsync(new CompleteUploadRequest
{
SessionId = sessionId,
FileHash = fileHash
});
if (!completeResponse.Success)
{
throw new Exception(completeResponse.Message);
}
}
}
private void UpdateProgress(ulong uploadedBytes, ulong totalBytes)
{
if (!this.DispatcherQueue.HasThreadAccess) // Check if the current thread has UI access
{
this.DispatcherQueue.TryEnqueue(() => UpdateProgress(uploadedBytes, totalBytes));
return;
}
progressBar.Value = (int)((double)uploadedBytes / totalBytes * 100);
lblProgress.Text = $"{FormatFileSize(uploadedBytes)} / {FormatFileSize(totalBytes)}";
lblPercentage.Text = $"{progressBar.Value}%";
}
private static string FormatFileSize(ulong bytes)
{
string[] sizes = ["B", "KB", "MB", "GB", "TB"];
var order = 0;
double len = bytes;
while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len /= 1024;
}
return $"{len:0.##} {sizes[order]}";
}
private void BtnPause_OnClick(object sender, RoutedEventArgs e)
{
_cancellationTokenSource?.Cancel();
btnPause.IsEnabled = false;
btnUpload.IsEnabled = true;
}
private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
{
_cancellationTokenSource?.Cancel();
btnCancel.IsEnabled = false;
btnPause.IsEnabled = false;
btnUpload.IsEnabled = true;
// 重置进度显示
progressBar.Value = 0;
lblProgress.Text = "";
lblPercentage.Text = "0%";
}
// Helper method for showing info dialogs
private async Task ShowInfoDialog(string content, string title)
{
var dialog = new ContentDialog
{
Title = title,
Content = content,
CloseButtonText = "确定",
XamlRoot = this.Content.XamlRoot
};
await dialog.ShowAsync();
}
// Helper method for showing error dialogs
private async Task ShowErrorDialog(string content, string title)
{
var dialog = new ContentDialog
{
Title = title,
Content = content,
CloseButtonText = "确定",
XamlRoot = this.Content.XamlRoot
};
await dialog.ShowAsync();
}
}
}

14
WinUINotes/HomePage.xaml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Page
x:Class="WinUINotes.HomePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WinUINotes"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<TextBlock Text="欢迎来到主页!" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Page>

View File

@ -0,0 +1,31 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace WinUINotes
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class HomePage : Page
{
public HomePage()
{
InitializeComponent();
}
}
}

View File

@ -14,7 +14,25 @@
</Window.SystemBackdrop>
<Grid>
<Frame x:Name="rootFrame" Grid.Row="1"
SourcePageType="local:NotePage"/>
<NavigationView
x:Name="NavigationViewControl"
IsBackButtonVisible="Auto"
IsSettingsVisible="True"
SelectionChanged="NavigationViewControl_SelectionChanged">
<NavigationView.MenuItems>
<NavigationViewItem Tag="HomePage" Icon="Home" Content="主页" />
<NavigationViewItem Tag="NotePage" Icon="Bookmarks" Content="笔记" />
<NavigationViewItem Tag="FileUploadPage" Icon="Upload" Content="文件上传"></NavigationViewItem>
<NavigationViewItemSeparator />
</NavigationView.MenuItems>
<NavigationView.FooterMenuItems>
<NavigationViewItem Tag="AboutPage" Icon="Help" Content="关于" />
</NavigationView.FooterMenuItems>
<Frame x:Name="ContentFrame" />
</NavigationView>
<!--<Frame x:Name="rootFrame" Grid.Row="1"
SourcePageType="local:NotePage"/>-->
</Grid>
</Window>

View File

@ -27,5 +27,34 @@ namespace WinUINotes
{
InitializeComponent();
}
private void NavigationViewControl_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
if (args.IsSettingsSelected)
{
ContentFrame.Navigate(typeof(SettingsPage));
}
else if (args.SelectedItem is NavigationViewItem selectedItem)
{
string tag = selectedItem.Tag?.ToString();
switch (tag)
{
case "HomePage":
ContentFrame.Navigate(typeof(HomePage));
break;
case "NotePage":
ContentFrame.Navigate(typeof(NotePage));
break;
case "AboutPage":
ContentFrame.Navigate(typeof(AboutPage));
break;
case "FileUploadPage":
ContentFrame.Navigate(typeof(FileUploadPage));
break;
// 可以添加更多 case 来处理其他导航项
}
}
}
}
}

17
WinUINotes/Model/Note.cs Normal file
View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WinUINotes.Model
{
public class Note
{
public string Content { get; set; }
public long UserId { get; set; }
public DateTime CreateTime { get; set; }
}
}

View File

@ -4,7 +4,7 @@ using Microsoft.UI.Xaml.Controls;
using System;
using Windows.Storage;
using Google.Protobuf.WellKnownTypes;
using ZR.Admin.Grpc;
using WinUINotes.Grpc;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

View File

@ -1,10 +1,15 @@
{
"profiles": {
"WinUINotes (Package)": {
"commandName": "MsixPackage"
"commandName": "MsixPackage",
"nativeDebugging": false
},
"WinUINotes (Unpackaged)": {
"commandName": "Project"
},
"WSL": {
"commandName": "WSL2",
"distributionName": ""
}
}
}

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Page
x:Class="WinUINotes.SettingsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WinUINotes"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<TextBlock Text="这是设置页面。" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Page>

View File

@ -0,0 +1,31 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace WinUINotes
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class SettingsPage : Page
{
public SettingsPage()
{
InitializeComponent();
}
}
}

View File

@ -13,7 +13,10 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Remove="AboutPage.xaml" />
<None Remove="HomePage.xaml" />
<None Remove="NotePage.xaml" />
<None Remove="SettingsPage.xaml" />
</ItemGroup>
<ItemGroup>
@ -45,6 +48,26 @@
<ItemGroup>
<ProjectReference Include="..\WinUINotes.Grpc\WinUINotes.Grpc.csproj" />
</ItemGroup>
<ItemGroup>
<Page Update="FileUploadPage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="AboutPage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="SettingsPage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="HomePage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="NotePage.xaml">
<Generator>MSBuild:Compile</Generator>

View File

@ -1,10 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup>
<ActiveDebugProfile>WinUINotes (Package)</ActiveDebugProfile>
</PropertyGroup>
<ItemGroup>
<Page Update="AboutPage.xaml">
<SubType>Designer</SubType>
</Page>
<None Update="App.xaml">
<SubType>Designer</SubType>
</None>
<Page Update="FileUploadPage.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="SettingsPage.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="HomePage.xaml">
<SubType>Designer</SubType>
</Page>
<None Update="MainWindow.xaml">
<SubType>Designer</SubType>
</None>