现在 Note 已拥有 State,请更新导航逻辑,将其传递回 AllNotesPage,在那里您可以根据其 State 进行相应处理。 这也使你有机会改善与导航相关的用户体验。
Tip
如果需要,请查看 创建第一个 WinUI 3 应用,步骤 1 - 导航。 在进行这些更改之前,了解导航的设置方式很有帮助。
目前,从 NotePage 后到回 AllNotesPage 的所有导航都是通过对 Frame.GoBack 的简单调用完成的。 但是,该方法 GoBack 不允许传递导航参数。 为了将 Note 作为参数传递,你需要将后退导航替换为前向导航(Frame.Navigate)。 此外,GoBack 不会像向前导航那样向导航堆栈添加条目,因此您需要管理后退堆栈,以防止此向前导航被添加。
Tip
可以从 WinUI Notes 第 2 部分的 GitHub 存储库下载或查看本教程的完整代码。 若要查看项目的起点和终点之间的差异,请参阅此提交: 第 2 部分的更新。
OnNavigatingFrom
在 NotePage.cs 中,重写 的 OnNavigatingFrom 方法。 在用户按下后退按钮并调用 GoBack 后调用此功能。 它允许你拦截导航、检查注释 State,并在需要时取消导航。
此处,如果未保存笔记,则取消后退导航并显示一个对话框,询问用户是否要保存笔记。
- 如果用户保存该笔记,则调用
SaveAsync,然后将返回导航替换为对Navigate的调用,并将该笔记传递给AllNotesPage。 - 如果用户未保存更改,请使用 TextBox.Undo 撤消任何编辑,重置笔记状态,然后重启后退导航。
// ↓ Add this. ↓
protected async override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
if (noteModel?.State == NoteState.Unsaved)
{
e.Cancel = true;
ContentDialog dialog = new ContentDialog();
// XamlRoot must be set for the ContentDialog.
dialog.XamlRoot = this.XamlRoot;
dialog.Title = "Save your work?";
dialog.PrimaryButtonText = "Save";
dialog.SecondaryButtonText = "Don't Save";
dialog.CloseButtonText = "Cancel";
dialog.DefaultButton = ContentDialogButton.Primary;
ContentDialogResult result = await dialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
await noteModel.SaveAsync();
Frame.Navigate(typeof(AllNotesPage), noteModel);
}
else if (result == ContentDialogResult.Secondary)
{
while (NoteEditor.CanUndo)
{
NoteEditor.Undo();
}
NoteEditor.Focus(FocusState.Programmatic);
noteModel.State = NoteState.Saved;
Frame.Navigate(typeof(AllNotesPage), noteModel);
}
}
}
Delete
接下来,修改 NotePage.xaml.cs 中删除按钮 Click 事件的代码。 你不会只是删除该笔记并返回,而是会检查该笔记的状态。
- 如果状态为
Unset- 这意味着笔记是新创建的,没有任何编辑,并且尚未保存 - 只需导航回去。 你无需将该说明作为参数传递。 - 否则,请从文件系统中删除笔记文件,并将
Note对象作为导航参数传回。 然后AllNotesPage将接收带有其Deleted状态的Note,并知道将其从Notes集合中删除。
private async void DeleteButton_Click(object sender, RoutedEventArgs e)
{
if (noteModel is not null)
{
if (noteModel.State == NoteState.Unset)
{
// If the note is new, doesn't have any edits,
// and hasn't been saved, just call GoBack.
// There's no need to pass back the noteModel.
if (Frame.CanGoBack == true)
{
Frame.GoBack();
}
}
else
{
// If the note has been saved before, then delete it
// and navigate back to the AllNotesPage passing the
// noteModel with its Deleted state.
await noteModel.DeleteAsync();
Frame.Navigate(typeof(AllNotesPage), noteModel);
}
}
}
保存并关闭
目前,用户必须单击以保存笔记,然后单击后退箭头关闭笔记页,然后返回到笔记集合。 通过允许用户保存和关闭笔记,只需单击一下即可改进此体验。 为此,你将将“保存”按钮替换为“保存并关闭” SplitButton ,并使用下拉列表选项来仅保存。
<!-- ↓ Delete this. ↓ -->
<!--<Button Content="Save" Click="SaveButton_Click"/>-->
<!-- ↓ Add this. ↓ -->
<SplitButton Content="Save & close" Click="SaveCloseButton_Click"
Height="32">
<SplitButton.Flyout>
<MenuFlyout>
<MenuFlyoutItem Text="Save" Click="SaveButton_Click"/>
</MenuFlyout>
</SplitButton.Flyout>
</SplitButton>
为“保存并关闭”按钮 Click 事件添加新事件处理程序。 在这里,先保存笔记,然后将其作为导航参数传回给 AllNotesPage。
// ↓ Add this. ↓
private async void SaveCloseButton_Click(SplitButton sender, SplitButtonClickEventArgs args)
{
if (noteModel is not null)
{
await noteModel.SaveAsync();
Frame.Navigate(typeof(AllNotesPage), noteModel);
}
}
处理 AllNotesPage 中的导航参数
在 AllNotesPage 中,您需要处理传入的导航参数(Note),并根据需要将其添加到 Notes 集合中或从中移除。
若要处理传入的导航参数,请重写 OnNavigatedTo 方法,如下所示。
// ↓ Add this. ↓
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is Note note)
{
if (note.State == NoteState.Deleted)
{
notesModel.RemoveNote(note);
}
else if (!notesModel.Notes.Contains(note))
{
notesModel.AddNote(note);
}
// This navigation should be treated like a
// back navigation, so clear the backstack.
Frame.BackStack.Clear();
}
}
现在,可以运行应用来了解这些更改的工作原理。 尝试添加新笔记、在笔记之间来回导航以及删除笔记。
在文档中了解详细信息:
后续步骤
恭喜! 你已完成 WinUI 说明第 2 部分 教程!
以下链接提供有关使用 WinUI 和 Windows 应用 SDK 创建应用的详细信息:
- 示例和资源
- Windows 应用设计
- 开发Windows桌面应用
- 适用于Windows应用的控件