2012-06-20 28 views
7

Khi sử dụng hộp văn bản.Undo(); Tôi nhận được lỗi sau:Không thể sử dụng Hoàn tác trong TextChanged

Cannot Undo or Redo while undo unit is open.

Bây giờ tôi hiểu tại sao đây là trường hợp (vì nó là một sự kiện không thể nén đang hoạt động) nhưng qua sự kiện gì tôi có thể thực hiện xác nhận trên một hộp văn bản và hoàn tác thay đổi nếu người dùng có đã nhập một ký tự không hợp lệ?

+0

Bạn nên sử dụng hành vi để thay thế. – SepehrM

+0

SepehrM - bạn có thể cung cấp một ví dụ không? Điều gì sẽ xảy ra nếu bạn KHÔNG muốn xác thực nhưng chỉ muốn dừng thông báo ngoại lệ chết tiệt này khi thổi phiên của bạn? Tôi nhận được điều này khi người dùng gõ một chút wee quá nhanh hoặc có thể dán một đoạn dữ liệu vào trường. Thậm chí không xác nhận. – Allen

Trả lời

6

Thay vì sử dụng Hoàn tác và Chuyển đổi văn bản, bạn nên sử dụng các sự kiện PreviewTextInputDataObject.Pasting. Trong trình xử lý sự kiện PreviewTextInput, hãy đặt e.Handled thành true nếu văn bản đã nhập là ký tự không hợp lệ. Trong trình xử lý sự kiện Pasting, hãy gọi e.CancelCommand() nếu văn bản được dán không hợp lệ.

Dưới đây là một ví dụ cho một hộp văn bản mà chỉ chấp nhận các chữ số 0 và 1:

XAML:

<Window x:Class="BinaryTextBox.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="133" Width="329"> 
    <StackPanel> 
     <TextBox x:Name="txtBinary" Width="100" Height="24" 
       PreviewTextInput="txtBinary_PreviewTextInput" 
       DataObject.Pasting="txtBinary_Pasting"/> 
    </StackPanel> 
</Window> 

Mã đằng sau:

using System.Text.RegularExpressions; 
using System.Windows; 
using System.Windows.Input; 

namespace BinaryTextBox 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     private void txtBinary_PreviewTextInput(object sender, 
       TextCompositionEventArgs e) 
     { 
      e.Handled = e.Text != "0" && e.Text != "1"; 
     } 

     private void txtBinary_Pasting(object sender, DataObjectPastingEventArgs e) 
     { 
      if (!Regex.IsMatch(e.DataObject.GetData(typeof(string)).ToString(), "^[01]+$")) 
      { 
       e.CancelCommand(); 
      } 
     } 
    } 
} 
+0

Brilliant - giải pháp hoàn hảo nhờ –

+0

Tuyệt vời, trình xử lý "dán" cũng xác thực nếu bạn đang chèn ký tự bằng cách kéo và thả. – Mishax

+0

Vấn đề với cách tiếp cận này là PreviewTextInput chỉ xem trước bất cứ điều gì đang được gõ, và không phải là kết quả cuối cùng.Điều này chỉ có thể hoạt động nếu người ta viết một thuật toán rất phức tạp và không thể duy trì để giải thích cho tất cả các đầu vào có thể có liên quan đến một giá trị hợp lệ. Ví dụ: trên một trường thập phân, hãy thử xác thực khi dấu trừ hoặc dấu chấm được áp dụng. Rõ ràng, bạn chỉ có thể gõ 1 của mỗi, nhưng không phải ở mọi điểm. Giải pháp tốt nhất là xác thực kết quả cuối cùng, _regardless_ về cách nó được đánh máy. WPF không có hỗ trợ cho như vậy, thật không may. – Neolisk

3

Gọi lùi lại không đồng bộ từ Từ trình xử lý sự kiện TextChanged:

Dispatcher.BeginInvoke(new Action(() => tb.Undo())) 
+0

Giải pháp này so sánh với câu trả lời được chấp nhận như thế nào? – InvalidBrainException

7

Để trả lời cách tiếp cận của simbay, tôi nghĩ rằng đang bị loại bỏ.

Bạn không thể gọi Hoàn tác trong TextChanged vì thao tác hoàn tác vẫn đang được chuẩn bị bởi TextBox. Nó dường như đôi khi hoạt động và không phải lúc khác, vì vậy điều này cho thấy có một điều kiện chủng tộc giữa khi sự kiện được báo hiệu và hoàn thành việc chuẩn bị hoàn tác.

Tuy nhiên, gọi Undo được gọi trên Dispatcher sẽ cho phép hộp văn bản hoàn thành quá trình hoàn tác hoàn tác của nó. Bạn có thể xác nhận kết quả của thay đổi văn bản và sau đó quyết định xem bạn có muốn giữ lại hoặc hoàn tác thay đổi hay không. Đây có thể không phải là cách tiếp cận tốt nhất, nhưng tôi đã thử nó và thổi một loạt các thay đổi văn bản và bột nhão vào hộp văn bản và không thể tái tạo ngoại lệ.

"Câu trả lời được chấp nhận" CHỈ là tuyệt vời nếu bạn muốn ngăn nhập hoặc dán ký tự không hợp lệ, nhưng nói chung tôi thường thực hiện xác thực nhiều hơn về nhập văn bản của hộp văn bản và muốn xác minh giá trị văn bản cuối cùng. Nó không dễ dàng để phân biệt các văn bản cuối cùng từ một sự kiện xem trước bởi vì như xa như kiểm soát được quan tâm không có gì đã xảy ra được nêu ra.

Để trả lời câu hỏi của Terribad, câu trả lời của simbay tốt hơn và gọn gàng hơn trong nhiều tình huống hơn.

tb.TextChanged =+ (sender, args) => 
{ 
    if(! MeetsMyExpectations(tb.Text)) 
     Dispatcher.BeginInvoke(new Action(() => tb.Undo())); 
} 

Tôi đã đọc rất nhiều cuộc phiêu lưu hoang dã trong xác thực hộp văn bản và điều này dễ dàng như tôi đã tìm thấy.

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