前言
作者:浪子花梦,一个有趣的程序员 ~
此文章将实现多个菜单的功能,其中的查找上一个 查找下一个菜单 是基于查找菜单实现的,替换菜单和查找菜单的实现方法差不多,还有跳转菜单的功能实现,最后还有窗口标题的转换器设置 . . .
前文如下所示:
【WPF高仿 Windows记事本】开发日记 (一) UI布局(帮助菜单功能实现
)
【WPF高仿 Windows记事本】开发日记 (二) 初步使用MVVM模式设计 帮助菜单 的三个命令
【WPF高仿 Windows记事本】开发日记 (三) 完善所有菜单的命令绑定并创建Models层的设计
【WPF高仿 Windows记事本】开发日记 (四) 菜单命令快捷键实现,实现查看菜单功能(三层架构初步使用
)
【WPF高仿 Windows记事本】开发日记 (五) 使用成熟的自动更新代码(ObservableObject)、实现是否显示状态栏功能、鼠标的滚轮命令绑定(查看菜单功能实现
)
【WPF高仿 Windows记事本】开发日记 (六) 自动换行、滚动条命令绑定,实现字体模式的选择功能(格式菜单功能实现
)
【WPF高仿 Windows记事本】开发日记 (七) 编辑菜单中的内置命令使用,查看与替换的窗口设计(包含窗口变为对话框)
【WPF高仿 Windows记事本】开发日记 (八) Bing搜索菜单功能实现,利用消息
和依赖注入
解除程序间的耦合
【WPF高仿 Windows记事本】开发日记 (九) interactivity交互事件使用,查找窗口功能实现,配置文件的序列化与反序列化
.
此文章实现的效果如下所示:
多菜单功能实现演示效果
.
查找上一个 查找下一个菜单
原版的notepad中,如果我们之前没有点击过查找窗口,那么点击查找上一个或者查找下一个菜单就会先弹出查找窗口,下面让我们先来实现这个功能 . . .
1)定义一个数据变量用于标记是否打开过查找窗口(false):
当我们打开查找窗口后,这个标记就为 true:
.
.
2)查找上一个与查找下一个菜单功能实现:
查找的方法与前文中的方法不一样了,因为在这里把实现成了静态类,方便多情况调用 . . .
.
.
3)提取并重构查找方法,代码如下:
using Notepad_WPF.Models;
using System;
using System.Windows;
namespace Notepad_WPF.Utility
{
public static class Tools
{
public static void OnFindTextCommand(DocumentModel documentModel, Direction direction = Direction.None)
{
int indexStart = 0; // 选择文本的起点
int indexFind = -1; // 查找到下/上一个文本的点
switch (direction)
{
case Direction.None:
// 向上查找
if (documentModel.IsFindUp)
{
FindPrev();
}
// 向下查找
else
{
FindNext();
}
break;
case Direction.Prev:
FindPrev();
break;
case Direction.Next:
FindNext();
break;
default:
break;
}
if (indexFind == -1) // 没有找到显示对话框
{
documentModel.TextBox.SelectionLength = 0;
documentModel.TextBox.SelectedText = "";
documentModel.TextBox.Focus();
MessageBox.Show("找不到“" + documentModel.FindText + "”", "记事本", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
documentModel.TextBox.Select(indexFind, documentModel.FindText.Length);
documentModel.TextBox.Focus(); // 聚焦到TextBox,作出相应的显示效果
void FindPrev()
{
indexStart = documentModel.TextBox.SelectionStart;
// 需要查找的文本 查找的起始点 是否区分大小写
if (documentModel.TextBox.Text.Length >= indexStart) // 防止越界的情况
{
indexFind = documentModel.TextBox.Text.LastIndexOf(documentModel.FindText,
indexStart,
documentModel.IsFindCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
}
// 判断是否选择了循环按钮
if (indexFind == -1)
{
if (documentModel.IsFindCirculated)
{
documentModel.TextBox.ScrollToEnd(); // 显示文本框的最下面
indexFind = documentModel.TextBox.Text.LastIndexOf(
documentModel.FindText,
documentModel.TextBox.Text.Length, // 文本框的最后面开始检索
documentModel.IsFindCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase
);
}
}
}
void FindNext()
{
// 加上本身的长度,不然向下查找到的就是本身
indexStart = documentModel.TextBox.SelectionStart + documentModel.FindText.Length;
if (documentModel.TextBox.Text.Length >= indexStart)
{
indexFind = documentModel.TextBox.Text.IndexOf(documentModel.FindText,
indexStart,
documentModel.IsFindCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
}
// 判断是否选择了循环按钮
if (indexFind == -1)
{
if (documentModel.IsFindCirculated)
{
documentModel.TextBox.ScrollToHome(); // 显示文本框的最下面
indexFind = documentModel.TextBox.Text.IndexOf(
documentModel.FindText,
0, // 文本框的最开始开始检索
documentModel.IsFindCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase
);
}
}
}
}
}
public enum Direction
{
None,
Prev,
Next
}
}
.
.
替换菜单窗口
大部分和查找菜单是一样的 . . .
1)定义两个用于处理替换的命令,一个是用于替换一个内容,另一个是替换所有的内容:
2)命令的方法逻辑实现:
ReplacedCommand:
在这里插入图片描述
ReplacedAllCommand:
.
.
跳转菜单窗口
1)界面设计及一些命令的初始化:
2)跳转窗口的逻辑功能实现:
.
.
时间菜单功能实现
.
.
窗口标题的转换器
1)定义两个变量,用于与主窗口标题进行绑定:
2)定义窗口标题的多值转换器:
3)单独创建一个资源字典,然后将主窗口的资源放入,在App.xaml 中引用,如下所示:
给窗口标题进行绑定,如下所示: