2012-06-27 21 views
15

Tôi đang cố gắng ràng buộc TextBox đến double thuộc tính của một số đối tượng với UpdateSourceTrigger=PropertyChanged. Mục tiêu là ngay lập tức trong khi chỉnh sửa xác thực giá trị đã nhập để ở trong phạm vi cho phép (và hiển thị lỗi nếu không). Tôi muốn triển khai xác thực ở cấp Mô hình, tức là thông qua IDataErrorInfo.Ràng buộc với trường đôi có xác nhận

Tất cả các công trình tuyệt vời khi tôi liên kết với thuộc tính int, nhưng nếu thuộc tính tăng gấp đôi thì hành vi chỉnh sửa bực bội xuất hiện: sau khi xóa chữ số quan trọng cuối cùng trong phần phân số - dấu tách thập phân sẽ tự động bị xóa (với tất cả các số phân số có thể phân số) . Ví dụ: sau khi xóa chữ số '3' khỏi số '12 .03 ', văn bản được thay đổi thành' 12 'thay vì '12 .0'.

Xin vui lòng, trợ giúp.

Đây là đoạn mã mẫu:

MainWindow.xaml:

<Window x:Class="BindWithValidation.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="80" Width="200" WindowStartupLocation="CenterOwner"> 

    <StackPanel> 
    <TextBox Width="100" Margin="10" Text="{Binding DoubleField, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"> 
     <TextBox.Style> 
     <Style TargetType="TextBox"> 
      <Style.Triggers> 
      <Trigger Property="Validation.HasError" Value="true"> 
       <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/> 
      </Trigger> 
      </Style.Triggers> 
     </Style> 
     </TextBox.Style> 
    </TextBox> 
    </StackPanel> 
</Window> 

MainWindow.xaml.cs:

namespace BindWithValidation 
{ 
    public partial class MainWindow : Window 
    { 
    private UISimpleData _uiData = new UISimpleData(); 

    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = _uiData; 
    } 
    } 
} 

UISimpleData.cs:

namespace BindWithValidation 
{ 
    public class UISimpleData : INotifyPropertyChanged, IDataErrorInfo 
    { 
    private double _doubleField = 12.03; 

    public double DoubleField 
    { 
     get 
     { 
     return _doubleField; 
     } 
     set 
     { 
     if (_doubleField == value) 
      return; 

     _doubleField = value; 
     RaisePropertyChanged("DoubleField"); 
     } 
    } 

    public string this[string propertyName] 
    { 
     get 
     { 
     string validationResult = null; 
     switch (propertyName) 
     { 
      case "DoubleField": 
      { 
      if (DoubleField < 2 || DoubleField > 5) 
       validationResult = "DoubleField is out of range"; 
      break; 
      } 

      default: 
      throw new ApplicationException("Unknown Property being validated on UIData"); 
     } 

     return validationResult; 
     } 
    } 

    public string Error { get { return "not implemented"; } } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected void RaisePropertyChanged(string property) 
    { 
     if (PropertyChanged != null) 
     PropertyChanged(this, new PropertyChangedEventArgs(property)); 
    } 
    } 
} 
+0

Tôi tưởng tượng điều này là để làm với định dạng - vì 12 là tương đương với 12,00, bạn đã thử sử dụng StringFormat trên ràng buộc? – Charleh

+0

Có, tôi đã thử, nhưng không thích cách chỉnh sửa hoạt động với nó. StringFormat là tốt cho trình bày, nhưng trong quá trình chỉnh sửa, tôi muốn tránh nó. – arudoy

Trả lời

1

Thử sử dụng StringFormat trên bi của bạn nding:

<TextBox Width="100" Margin="10" Text="{Binding DoubleField, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, StringFormat='0.0'}"> 

Không chắc rằng định dạng chuỗi là thậm chí ngay từ khi tôi đã không được thực hiện một trong một thời gian nhưng nó chỉ là một ví dụ

+0

Cảm ơn đề xuất của bạn, nhưng StringFormat không thuận tiện (xem nhận xét của tôi ở trên). Nếu thực tế, tôi sẽ áp dụng StringFormat sau khi TextBox sẽ mất tập trung, nhưng trong khi nó có tiêu điểm tôi muốn tránh StringFormat – arudoy

5

Cố gắng định dạng giá trị với chữ số thập phân?

Nó có thể là lạ mặc dù kể từ khi bạn sẽ luôn luôn có N chữ số thập phân.

<TextBox.Text> 
    <Binding Path="DoubleField" StringFormat="{}{0:0.00}" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True"/> 
</TextBox.Text> 

Nếu có dấu thập phân cố định không đủ tốt, bạn có thể phải viết trình biến đổi xử lý giá trị dưới dạng chuỗi và chuyển đổi thành giá trị gấp đôi.

+0

Vâng, tôi đã thử. Với kích hoạt tính năng chỉnh sửa StringFormat hoạt động cũng không phải là rất tốt. Ví dụ: với dấu phân tách dấu thập phân của StringFormat của bạn với phím xóa từ '12 .00 'dẫn đến' 1200.00 'với con trỏ sau' 12 '. Vì vậy, không thể xóa toàn bộ phần phân đoạn có thể gây ngạc nhiên cho người dùng. – arudoy

+0

Tôi cũng đã cố gắng để viết trình chuyển đổi của riêng tôi. Chuyển đổi từ chuỗi thành hai công trình ok, nhưng có một vấn đề với chuyển đổi ngược lại: làm thế nào có thể chuyển đổi biết rằng nó nên chèn dấu phân cách thập phân vào chuỗi đại diện của giá trị 12? Người dùng có thể nhập '12' hoặc '12 '. hoặc thậm chí '12 .0 'và tất cả những thứ này đều có giá trị 12 được chuyển đến công cụ chuyển đổi – arudoy

+0

Đây chính xác là lý do tại sao hành vi mặc định là làm như thế nào. Sẽ rất khó để đoán giá trị nhìn thấy được là gì nếu UI không có "trạng thái" - có thể điều khiển tùy chỉnh có thể thực hiện công việc:/ –

9

Tôi nhận ra mình hơi muộn một chút nhưng tôi đã tìm được giải pháp khá sạch sẽ cho vấn đề này.

Bộ chuyển đổi thông minh ghi nhớ chuỗi cuối cùng được chuyển đổi thành gấp đôi và trả về nếu nó tồn tại nên làm mọi thứ bạn muốn.

Lưu ý rằng khi người dùng thay đổi nội dung của hộp văn bản, ConvertBack sẽ lưu chuỗi đầu vào của người dùng, phân tích chuỗi cho giá trị gấp đôi và chuyển giá trị đó cho mô hình chế độ xem. Ngay sau đó, Chuyển đổi được gọi để hiển thị giá trị mới thay đổi. Tại thời điểm này, chuỗi được lưu trữ không phải là null và sẽ được trả về.

Nếu ứng dụng thay vì người dùng làm cho đôi thay đổi chỉ chuyển đổi được gọi. Điều này có nghĩa là chuỗi được lưu trữ sẽ là null và một ToString() chuẩn sẽ được gọi là double.

Bằng cách này, người dùng tránh những bất ngờ lạ khi sửa đổi nội dung của hộp văn bản nhưng ứng dụng vẫn có thể kích hoạt thay đổi.

public class DoubleToPersistantStringConverter : IValueConverter 
{ 
    private string lastConvertBackString; 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     if (!(value is double)) return null; 

     var stringValue = lastConvertBackString ?? value.ToString(); 
     lastConvertBackString = null; 

     return stringValue; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     if (!(value is string)) return null; 

     double result; 
     if (double.TryParse((string)value, out result)) 
     { 
      lastConvertBackString = (string)value; 
      return result; 
     } 

     return null; 
    } 
} 
+0

Đây là một giải pháp tốt. Tuy nhiên, nó sẽ làm rối tung mọi thứ khi gọi NotifyPropertyChanged cùng một lúc trên nhiều TextBox bằng trình chuyển đổi này. Tôi đề nghị chuyển thuộc tính như một tham số cho trình biến đổi và thay thế 'lastConvertBackString' bằng một' Dictionary '. Bằng cách đó bạn có thể nhớ chuỗi cuối cùng cho mỗi thuộc tính. – Octan

2

tôi đã chạy vào cùng một vấn đề, và đã tìm thấy một giải pháp khá đơn giản: "" sử dụng một validator tùy chỉnh, mà không trả lại "hợp lệ" khi các văn bản kết thúc bằng hoặc "0":

double val = 0; 
string tmp = value.ToString(); 

if (tmp.EndsWith(",") || tmp.EndsWith("0") || tmp.EndsWith(".")) 
{ 
    return new ValidationResult(false, "Enter another digit, or delete the last one."); 
} 
else 
{ 
    return ValidationResult.ValidResult; 
} 
+0

Tôi nghĩ rằng nó sẽ hiển thị lỗi nếu tôi nhập 100 –

+0

Đúng. Thêm một '' tmp.Contains (',') || tmp.Contains ('.') '' trong kiểm tra '' EndsWith (".") '' để tránh điều này. – Digifaktur

3

Vấn đề là bạn đang cập nhật thuộc tính của mình mỗi khi giá trị thay đổi. Khi bạn thay đổi 12,03-12,0 nó được làm tròn đến 12.

Bạn có thể thấy những thay đổi bằng cách cung cấp delay bằng cách thay đổi TextBox trong xaml như thế này

<TextBox Width="100" Margin="10" Text="{Binding DoubleField, UpdateSourceTrigger=PropertyChanged,Delay=500, ValidatesOnDataErrors=True}"> 

nhưng delay sẽ thông báo và thiết lập thuộc tính sau thời gian trễ trong giây phút. Better sử dụng StringFormat như thế này

<TextBox Width="100" Margin="10" Text="{Binding DoubleField, UpdateSourceTrigger=PropertyChanged,StringFormat=N2, ValidatesOnDataErrors=True}"> 
5

Hành vi của ràng buộc giá trị float để một hộp đã được thay đổi từ NET 4-4,5. Với .NET 4.5, bạn không còn có thể nhập ký tự dấu phân tách (dấu phẩy hoặc dấu chấm) với 'UpdateSourceTrigger = PropertyChanged' theo mặc định.

Microsoft cho biết, điều này (là) dành

Nếu bạn vẫn muốn sử dụng 'UpdateSourceTrigger = PropertyChanged', bạn có thể buộc các hành vi NET 4 trong .NET 4.5 ứng dụng của bạn bằng cách thêm sau dòng mã để các nhà xây dựng của App.xaml.cs của bạn:

public App() 
{ 
    System.Windows.FrameworkCompatibilityPreferences 
       .KeepTextBoxDisplaySynchronizedWithTextProperty = false; 
} 

(Sebastian Lux - sao chép nguyên văn từ here)

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