2010-06-15 28 views
7

Tôi đang cố gắng để có được đầu của tôi xung quanh lớp TextPointer trong một RichTextBox WPF.Làm thế nào để theo dõi TextPointer trong WPF RichTextBox?

Tôi muốn có thể theo dõi chúng để tôi có thể kết hợp thông tin với các khu vực trong văn bản.

Tôi hiện đang làm việc với một ví dụ rất đơn giản để thử và tìm ra những gì đang diễn ra. Trong sự kiện PreviewKeyDown tôi đang lưu trữ vị trí dấu mũ và sau đó trong sự kiện PreviewKeyUp tôi đang tạo một TextRange dựa trên các vị trí trước và sau dấu nháy. Đây là một mẫu mã minh họa những gì tôi đang cố gắng làm:

// The caret position before typing 
private TextPointer caretBefore = null; 

private void rtbTest_PreviewKeyDown(object sender, KeyEventArgs e) 
{ 
    // Store caret position 
    caretBefore = rtbTest.CaretPosition; 
} 

private void rtbTest_PreviewKeyUp(object sender, KeyEventArgs e) 
{ 
    // Get text between before and after caret positions 
    TextRange tr = new TextRange(caretBefore, rtbTest.CaretPosition); 
    MessageBox.Show(tr.Text); 
} 

Vấn đề là văn bản mà tôi nhận được để trống. Ví dụ: nếu tôi nhập ký tự 'a' thì tôi sẽ tìm văn bản "a" trong TextRange.

Có ai biết điều gì đang xảy ra không? Nó có thể là một cái gì đó rất đơn giản nhưng tôi đã dành một buổi chiều đi đâu đó.

Tôi đang cố gắng nắm lấy công nghệ WPF mới nhưng thấy rằng RichTextBox đặc biệt phức tạp đến nỗi nó thậm chí còn làm những việc đơn giản như thế này khó khăn. Nếu bất cứ ai có bất kỳ liên kết nào làm tốt công việc giải thích TextPointer, tôi sẽ đánh giá cao nếu bạn có thể cho tôi biết.

Trả lời

19

Khi bạn thêm và xóa văn bản khỏi FlowDocument, tất cả TextPointers điều chỉnh vị trí dựa trên số lượng chẩn đoán được thiết kế để làm cho chúng ở gần cùng một "địa điểm" nhất có thể.

Để xóa thao tác này rất đơn giản: Nếu TextPointer nằm trong văn bản đã xóa, nó kết thúc bằng cách chia sẻ các ký tự xung quanh văn bản đã xóa. Nhưng đối với chèn nó không đơn giản như vậy: Khi văn bản hoặc các yếu tố khác được chèn vào một FlowDocument chính xác tại một TextPointer hiện có, nên TextPointer kết thúc trước hoặc sau khi chèn văn bản? TextPointer có một thuộc tính được gọi là "LogicalDirection" để kiểm soát điều này.

Điều đang xảy ra trong trường hợp của bạn là vị trí "caretBefore" bạn đang chụp chính xác là vị trí đặt văn bản, trong trường hợp thử nghiệm của bạn LogicalDirection là LogicalDirection.Forward. Vì vậy, khi ký tự được chèn vào, "caretBefore" của bạn kết thúc lên sau ký tự được chèn, trùng với TextPosition cho bạn một TextRange trống.

Làm thế nào để một TextPointer nhận được một LogicalDirection được gán cho nó? Nếu bạn nhấp vào RichTextBox để đặt vị trí dấu mũ, thì nhấp chuột được hiểu là nằm giữa hai ký tự. Nếu điểm thực tế bạn nhấp vào là ký tự thứ hai, LogicalDirection được đặt là Chuyển tiếp, nhưng nếu điểm thực tế bạn nhấp vào là ký tự đầu tiên, LogicalDirection được đặt thành Quay lại.

Hãy thử thí nghiệm này:

  1. Đặt FontSize của bạn = "40" và prepopulate RichTextBox với dòng chữ "ABCD" trong constructor
  2. Bấm vào phía bên phải của B và gõ một chữ "X "giữa B và C. LogicalDirection là Backward, vì vậy" beforeCaret "của bạn kết thúc trước" X "và MessageBox của bạn hiển thị" X ".
  3. Nhấp vào bên trái của C và nhập "X" giữa B và C. LogicalDirection là Chuyển tiếp, vì vậy "beforeCaret" của bạn kết thúc sau "X" và MessageBox của bạn trống.

Hành vi này phản trực giác: Khi bạn không biết rằng LogicalDirection tồn tại, bạn sẽ nghĩ rằng nhấp vào bên phải của B hoặc bên trái của C sẽ cho bạn chính xác vị trí dấu mũ.

Lưu ý: Một cách dễ dàng để hình dung những gì đang xảy ra là chỉ huy ra MessageBox.Show của bạn và thay vào đó làm một caretBefore.InsertTextInRun("^");

Làm thế nào để bạn đạt được kết quả bạn cần? LogicalDirection là chỉ đọc. Một cách là sử dụng TextRange để buộc xây dựng một TextPointer với một LogicalDirection của Backward:

caretBefore = new TextRange(caretBefore, caretBefore.DocumentEnd).Start; 

Thực hiện việc này trong PreviewKeyDown. Nếu bạn đợi cho đến khi PreviewKeyUp nó đã quá muộn: caretBefore đã di chuyển. Điều này làm việc bởi vì theo như tôi có thể nói, sự bắt đầu của một TextRange không rỗng luôn có một LogicalDirection của Backward.

Một tùy chọn khác là lưu bù đắp biểu tượng từ đầu tài liệu (lưu ý rằng đây không phải là ký tự bù đắp!). Trong trường hợp này bạn có thể lưu trữ offset trong PreviewKeyDown:

caretBeforeOffset = caretBefore.DocumentStart.OffsetToPosition(caretBefore); 

và đặt lại caretBefore để cùng một biểu tượng bù đắp trong PreviewKeyUp:

caretBefore = caretBefore.DocumentStart.GetPositionAtOffset(caretBeforeOffset, 
                  LogicalDirection.Forward); 

Mặc dù công trình này nó không phải là chung như buộc TextPointer của bạn để có một LogicalDirection của Backward: Bất kỳ văn bản thay đổi trước đó trong tài liệu giữa PreviewKeyDown và PreviewKeyUp sẽ gây ra tính toán bù đắp biểu tượng để tìm vị trí sai, đó là những gì TextPointers được thiết kế để sửa chữa ngay từ đầu.

Tôi không biết bất kỳ tài nguyên nào tốt để tìm hiểu về TextPointers ngoại trừ việc đọc tài liệu và chơi với chúng, đó chính xác là những gì bạn đã làm.

+0

Hi Ray, Cảm ơn rất nhiều vì đã trả lời đầy đủ thông tin. Nó được đánh giá cao và chắc chắn giúp mọi thứ rõ ràng cho tôi về các hướng hợp lý - Tôi đã thử nghiệm của bạn. Điều cuối cùng tôi dự tính thực hiện là xử lý dòng tài liệu theo từng dòng. Tôi biết về phương pháp GetLineStartPosition nhưng tự hỏi nếu bạn biết làm thế nào để có được vị trí của sự kết thúc của dòng từ một TextPointer? Cảm ơn bạn lần nữa, Alan –

+0

Bạn có thể kiểm soát cách GetLineStartPosition di chuyển bằng cách thay đổi số bạn vượt qua. Nếu bạn muốn biết thêm chi tiết về cách thức hoạt động và cách sử dụng để đạt được vị trí cuối cùng, vui lòng đăng câu hỏi khác tại đây StackOverflow. Có đủ để giải thích rằng nó đảm bảo một câu hỏi và câu trả lời riêng biệt. Ngoài ra khả năng định dạng trong các ý kiến ​​này là rất hạn chế. –

+0

Hi Ray, Cảm ơn bạn đã liên hệ lại với tôi. Tôi đánh giá cao những giới hạn của nhận xét và đã đăng câu hỏi mới tại đây: http://stackoverflow.com/questions/3060108/using-getlinestartposition-to-get-the-end-of-a-line-in-wpf- richtextbox –

Các vấn đề liên quan