【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现

【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现_第1张图片

前言

作者:浪子花梦,一个有趣的程序员 ~
此文章将实现多个菜单的功能,其中的查找上一个 查找下一个菜单 是基于查找菜单实现的,替换菜单和查找菜单的实现方法差不多,还有跳转菜单的功能实现,最后还有窗口标题的转换器设置 . . .

前文如下所示:
【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:
【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现_第2张图片
.
.

2)查找上一个与查找下一个菜单功能实现:
【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现_第3张图片
查找的方法与前文中的方法不一样了,因为在这里把实现成了静态类,方便多情况调用 . . .

.
.

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)定义两个用于处理替换的命令,一个是用于替换一个内容,另一个是替换所有的内容:
【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现_第4张图片
2)命令的方法逻辑实现:
ReplacedCommand:
在这里插入图片描述
ReplacedAllCommand:
【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现_第5张图片
.
.

跳转菜单窗口

1)界面设计及一些命令的初始化:
【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现_第6张图片
【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现_第7张图片
2)跳转窗口的逻辑功能实现:
【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现_第8张图片
.
.

时间菜单功能实现

【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现_第9张图片
.
.

窗口标题的转换器

1)定义两个变量,用于与主窗口标题进行绑定:
【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现_第10张图片
2)定义窗口标题的多值转换器:
【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现_第11张图片
3)单独创建一个资源字典,然后将主窗口的资源放入,在App.xaml 中引用,如下所示:
【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现_第12张图片
【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现_第13张图片
给窗口标题进行绑定,如下所示:
【WPF高仿 Windows记事本】开发日记 (十) 查找上一个与查找下一个 替换菜单 跳转菜单 时间菜单与窗口标题的转换器功能实现_第14张图片

你可能感兴趣的:(记事本开发日记,WPF记事本开发,WPF小项目)