C# – Tạo Find and Replace dialog cho RichTextBox

Mặc dù RichTextBox đã hỗ trợ sẵn phương thức Find, tuy nhiên nhiều người vẫn thắc mắc về hiện thực chức năng Find Next cho control này. Để giải quyết vấn đề này, tôi sẽ minh họa cách tạo một cửa sổ Find and Replace đơn giản như trong Notepad.

Download sourcecode+demo(29KB)

RichTextBox hỗ trợ nhiều phiên bản của phương thức Find. Một overload cơ bản mà ta sẽ dùng để tìm kiếm trong RichTextBox là:

public int Find(
	string str,
	int start,
	RichTextBoxFinds options
)

Trong đó:

  • str: Chuỗi tìm kiếm
  • start: Vị trí bắt đầu tìm kiếm, đặt là vị trí cuối cùng của vùng chọn trong RichTextBox để Find Next.
  • options: Các tùy chọn tìm kiếm (như match case, match whole word,…). Bạn có thể kết hợp các tùy chọn lại bằng toán tử bitwise OR ‘|’

Phương thức này sẽ trả về vị trí của chuỗi được tìm thấy, sau đó ta kết hợp với chiều dài của chuỗi cần tìm để tạo vùng chọn (highlight) trong RichTextBox.

Mặc định Find() sẽ tìm kiếm từ trên xuống dưới, để tìm kiếm theo hướng ngược lại, ta cần dùng tùy chọn RichTextBoxFinds.Reverse, đồng thời sử dụng một phiên bản khác của Find() để tìm kiếm từ vị trí đầu tiên đến vị trí hiện tại của cursor trong RichTextBox:

public int Find(
	string str,
	int start,
	int end,
	RichTextBoxFinds options
)

Các điểm cần chú ý:

– RichTextBox.HideSelecion=false : Hiển thị vùng chọn trong RichTextBox khi không được focus.

– Sử dụng Form.Show(IWin32Window) để form Find luôn hiển thị lên trên form Main, và có thể chuyển focus qua lại 2 form.

– Thay đổi ClientSize.Height thay vì Form.Height, vì Form.Height bao gồm luôn cả titlebar.

Ok! Rất đơn giản, vậy ta có thể tạo một form có chức năng Find Next và Replace như sau:

FindForm.cs

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Demo_Editor
{
	public partial class FindForm : Form
	{
		RichTextBox _richTextBox;

		bool _close;

		public FindForm(RichTextBox richTextBox)
		{
			InitializeComponent();

			_richTextBox=richTextBox;
		}

		protected override void OnFormClosing(FormClosingEventArgs e)
		{
			if(!_close)
			{
				// hide instead of close
				this.Hide();
				e.Cancel=true;
			}

			base.OnFormClosing(e);
		}
		public void ForceClose()
		{
			_close=true;
			this.Close();
		}

		public void ShowFind(bool replaceMode)
		{
			this.Text= replaceMode ? "Find" : "Replace";
			pnlReplace.Visible=replaceMode;

			if(!this.Visible)
				this.Show(_richTextBox);
			// resize form
			this.ClientSize = new Size(this.ClientSize.Width,pnlOptions.Bottom);

			txtFindText.Focus();
			txtFindText.SelectAll();
		}

		void BtnFindNextClick(object sender, EventArgs e)
		{
			Find(_richTextBox, txtFindText.Text,chkMatchCase.Checked,chkMatchWholeWord.Checked,radDirectionUp.Checked);
		}
		void Find(RichTextBox richText, string text, bool matchCase, bool matchWholeWord, bool upDirection)
		{
			RichTextBoxFinds options=RichTextBoxFinds.None;
			if(matchCase)
				options|= RichTextBoxFinds.MatchCase;
			if(matchWholeWord)
				options|=RichTextBoxFinds.WholeWord;
			if(upDirection)
				options|=RichTextBoxFinds.Reverse;

			int index;
			if(upDirection)
				index = richText.Find(text,0,richText.SelectionStart,options);
			else
				index = richText.Find(text,richText.SelectionStart+richText.SelectionLength,options);

			if(index>=0)
			{
				richText.SelectionStart=index;
				richText.SelectionLength=text.Length;
			}
			else // text not found
			{
				MessageBox.Show(Application.ProductName + " has finished searching the document.",
				                Application.ProductName,MessageBoxButtons.OK,
				                MessageBoxIcon.Information);
			}
		}

		void BtnReplaceClick(object sender, EventArgs e)
		{
			_richTextBox.SelectedText=txtReplace.Text;
		}

		void BtnReplaceAllClick(object sender, EventArgs e)
		{
			_richTextBox.Text=_richTextBox.Text.Replace(txtFindText.Text,txtReplace.Text);
		}
	}
}

Cách sử dung:
FormMain.cs

using System;
using System.Windows.Forms;

namespace Demo_Editor
{
	public partial class MainForm : Form
	{
		FindForm _findForm;
		public MainForm()
		{
			InitializeComponent();
		}
		protected override void OnFormClosing(FormClosingEventArgs e)
		{
			if(_findForm!=null)
				_findForm.ForceClose();

			// if there are unclosed forms in your application,
			// e.Cancel will be true
			e.Cancel=false;

			base.OnFormClosing(e);
		}
		void BtnFindClick(object sender, EventArgs e)
		{
			if(_findForm==null || _findForm.IsDisposed)
				_findForm=new FindForm(this,richTextBox1);
			_findForm.ShowFind(false);
		}

		void BtnReplaceClick(object sender, EventArgs e)
		{
			if(_findForm==null || _findForm.IsDisposed)
				_findForm=new FindForm(this,richTextBox1);
			_findForm.ShowFind(true);
		}
	}
}

Đây chỉ là ví dụ minh họa đơn giản nên chưa xét hết các trường hợp lỗi. Bạn có thể tạo một sub class của RichTextBox và tích hợp hộp thoại Find & Replace này vào, hoặc cũng có thể build ra một thư viện riêng để sử dụng khi cần thiết.

https://yinyangit.wordpress.com

Advertisements

4 thoughts on “C# – Tạo Find and Replace dialog cho RichTextBox

  1. Demo ngon quá rồi 🙂

    Mình xin góp ý nhỏ: program có chút lỗi, cụ thể khi ấn Replace mà ko ấn Find Next trước là nó sẽ thêm giá trị vào đoạn text cũ !
    Bạn sửa

    void BtnReplaceClick(object sender, EventArgs e)
    {
    _richTextBox.SelectedText=txtReplace.Text;
    }

    thành

    void BtnReplaceClick(object sender, EventArgs e)
    {
    if (_richTextBox.SelectedText != “”)
    _richTextBox.SelectedText=txtReplace.Text;
    }

    Chả biết đã chuẩn chưa, thấy chạy tạm thời ổn cả 🙂

    Thanx và cố gắng phát huy blog nhé !

    Phản hồi
  2. oh đúng là sai thật, nhờ lưu lý của bạn mình đã xem lại và bạn có thể sửa lại như sau (cho chức năng Replace):

    – Kiếm tra TextBox ‘Find what’ phải khác rỗng.
    – Nếu RichTextBox có chuỗi được chọn bằng với ‘Find what’ thì tiến hành Replace.
    – Gọi Find() để tìm đến chuỗi tiếp theo.

    Cảm ơn bạn!

    Phản hồi

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Đăng xuất / Thay đổi )

Connecting to %s