【WPF高仿 Windows记事本】开发日记 (九) interactivity交互事件使用,查找窗口功能实现,配置文件的序列化与反序列化

在这里插入图片描述

前言

作者:浪子花梦,一个有趣的程序员 ~
此文将完成interactivity事件的使用,为什么需要用到这个功能呢?因为程序中需要使用加载事件,如果我们需要将事件处理器定义在隐藏代码中,这就破坏了MVVM设计模式了,使用interactivity可以很好的与业务逻辑中的命令进行绑定,实现解耦,另外,此文章将实现查找窗口的功能,搜索指定的文本内容,在上面的演示上展示过了,包括一些细节很重要的知识点,另外还有使用配置文件将程序中一些数据保存下来,已供下次程序运行时加载初始化 . . .

前文如下所示:
【WPF高仿 Windows记事本】开发日记 (一) UI布局(帮助菜单功能实现)
【WPF高仿 Windows记事本】开发日记 (二) 初步使用MVVM模式设计 帮助菜单 的三个命令
【WPF高仿 Windows记事本】开发日记 (三) 完善所有菜单的命令绑定并创建Models层的设计
【WPF高仿 Windows记事本】开发日记 (四) 菜单命令快捷键实现,实现查看菜单功能(三层架构初步使用
【WPF高仿 Windows记事本】开发日记 (五) 使用成熟的自动更新代码(ObservableObject)、实现是否显示状态栏功能、鼠标的滚轮命令绑定(查看菜单功能实现)
【WPF高仿 Windows记事本】开发日记 (六) 自动换行、滚动条命令绑定,实现字体模式的选择功能(格式菜单功能实现
【WPF高仿 Windows记事本】开发日记 (七) 编辑菜单中的内置命令使用,查看与替换的窗口设计(包含窗口变为对话框)
【WPF高仿 Windows记事本】开发日记 (八) Bing搜索菜单功能实现,利用消息依赖注入解除程序间的耦合

.

此文章实现的效果如下所示:

查找窗口功能演示


1)如果想用交互事件,并且不安装第三方插件的情况下,需要定义如下的类:
在这里插入图片描述
.
.

2)DocumentModel 数据层的类中定义TextBox类型,所有的操作都基于此实现:
在这里插入图片描述
.
.

3)MainWindow.xaml 中使用interactivity绑定程序加载事件相关的命令:
在这里插入图片描述
此命令有个参数是 textBox,代表主文本框,方法实现如下所示,将这个文本框赋值给数据层:
在这里插入图片描述
.
.

4)主文本框的两个属性注意:选中时的颜色,失去焦点时是否允许高度:
在这里插入图片描述
.
.

5)查找窗口初始加载时,绑定命令,选中所有的文本框内容:
在这里插入图片描述
在这里插入图片描述
命令响应方法如下:
在这里插入图片描述
.
.

6)发送消息打开查找窗口时,判断是否选中了主文本中的内容,并给查找窗口中的文本内容赋值:
在这里插入图片描述
.
.

7)查找下一个 和 取消按钮的命令与实现逻辑如下所示:
xaml代码部分:
在这里插入图片描述
命令初始化:
在这里插入图片描述
逻辑实现:

private void OnCancelCommand(Window window)
{
    window.Close();             // 关闭窗口
}

private void OnFindTextCommandArgs(TextBox textBox)
{
    OnFindTextCommand();        // 查找文本的逻辑实现
    textBox.Focus();            // 解决按钮热点无法一直按的bug
}

private void OnFindTextCommand()
{
    int indexStart = 0;     // 选择文本的起点
    int indexFind = 0;      // 查找到下/上一个文本的点

    // 向上查找
    if (this.DocumentModel.IsFindUp)
    {
        indexStart = this.DocumentModel.TextBox.SelectionStart;

        // 需要查找的文本  查找的起始点  是否区分大小写
        indexFind = this.DocumentModel.TextBox.Text.LastIndexOf(
            this.DocumentModel.FindText,
            indexStart,
            this.DocumentModel.IsFindCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);


        // 判断是否选择了循环按钮
        if (indexFind == -1)
        {
            if (this.DocumentModel.IsFindCirculated)
            {
                this.DocumentModel.TextBox.ScrollToEnd();   // 显示文本框的最下面
                indexFind = this.DocumentModel.TextBox.Text.LastIndexOf(
                    this.DocumentModel.FindText,
                    this.DocumentModel.TextBox.Text.Length, // 文本框的最后面开始检索
                    this.DocumentModel.IsFindCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase
                    );
            }
        }
    }
    // 向下查找
    else
    {
        // 加上本身的长度,不然向下查找到的就是本身
        indexStart = this.DocumentModel.TextBox.SelectionStart + this.DocumentModel.FindText.Length;

        indexFind = this.DocumentModel.TextBox.Text.IndexOf(
            this.DocumentModel.FindText,
            indexStart,
            this.DocumentModel.IsFindCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);


        // 判断是否选择了循环按钮
        if (indexFind == -1)
        {
            if (this.DocumentModel.IsFindCirculated)
            {
                this.DocumentModel.TextBox.ScrollToHome();   // 显示文本框的最下面
                indexFind = this.DocumentModel.TextBox.Text.IndexOf(
                    this.DocumentModel.FindText,
                    0,                                       // 文本框的最开始开始检索
                    this.DocumentModel.IsFindCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase
                    );
            }
        }
    }

    if (indexFind == -1)         // 没有找到显示对话框
    {
        MessageBox.Show("找不到“" + this.DocumentModel.FindText + "”", "记事本", MessageBoxButton.OK, MessageBoxImage.Information);
        return;
    }

    this.DocumentModel.TextBox.Select(indexFind, this.DocumentModel.FindText.Length);
    this.DocumentModel.TextBox.Focus();         // 聚焦到TextBox,作出相应的显示效果
}

.
.

8)在数据层中新建一个类,用于序列化与反序列化(其中用于保存一些需要的字段):

using System;
using System.Runtime.Serialization;

namespace Notepad_WPF.Models
{
    [Serializable]
    public class SavedSettings : ISerializable
    {
        public String FindText;
        public Boolean IsFindCaseSensitive;
        public Boolean IsFindCirculated;
        public Boolean IsFindUp;
        public String ReplacedText;

        public SavedSettings()
        {

        }

        // 当类被序列化时,做出的一些操作
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("FindText", FindText, typeof(String));
            info.AddValue("IsFindCaseSensitive", IsFindCaseSensitive, typeof(Boolean));
            info.AddValue("IsFindCirculated", IsFindCirculated, typeof(Boolean));
            info.AddValue("IsFindUp", IsFindUp, typeof(Boolean));
            info.AddValue("ReplacedText", ReplacedText, typeof(String));
        }


        // 反序列时,从配置文件中加载数据,返回 SavedSettings对象
        public SavedSettings(SerializationInfo info, StreamingContext context)
        {
            FindText = info.GetString("FindText");
            IsFindCaseSensitive = info.GetBoolean("IsFindCaseSensitive");
            IsFindCirculated = info.GetBoolean("IsFindCirculated");
            IsFindUp = info.GetBoolean("IsFindUp");
            ReplacedText = info.GetString("ReplacedText");
        }
    }
}

.
.

9)在数据层DocumentModel类中定义两个方法,用于保存和加载配置文件中的数据:
保存数据到配置文件中(序列化):
在这里插入图片描述
从配置文件中加载数据到DocumentModel类的实例中(反序列化):
在这里插入图片描述
当DocumentModel类被实例时,加载数据:
在这里插入图片描述
当查找窗口被打开时,保存数据(临时数据):
在这里插入图片描述
当按下取消按钮时,数据还原到窗口没打开时的数据状态:
在这里插入图片描述
当按下查找按钮时,保存最新的数据:
在这里插入图片描述
.
.


猜你喜欢

转载自blog.csdn.net/weixin_42100963/article/details/107643542