[英]WPF Data Binding exception handling
我有一個綁定到 Integer 屬性的文本框。 當用戶在文本框中輸入無法轉換為 integer(例如名稱)的內容時,將引發異常並且原始屬性值不會更改。 我想捕獲異常以便我可以禁用連接到該屬性的命令? 一般來說,如果可能的話,我該如何從定義屬性的視圖 model 中做到這一點?
我最近遇到了同樣的問題,並且我使用行為來解決它(但如果你不想要,你就不需要它們,它只是為了重用我在不同視圖中需要的代碼)。 主要思想是在ViewModel中定義一些方法,允許視圖通知ViewModel無法檢測到的輸入中的錯誤。
因此,首先在ViewModel中定義這些方法。 為簡單起見,我只會跟蹤錯誤的數量,但您可以存儲更多關於它們的信息(如實際錯誤):
private int _errorCount = 0;
void AddUIValidationError()
{
_errorCount++;
}
void RemoveUIValidationError()
{
_errorCount--;
}
然后,在View中,注冊System.Windows.Controls.Validation.ErrorEvent
,這是一個路由事件,可以讓您知道組件(先前配置為通知數據錯誤)何時檢測到錯誤(如異常驗證錯誤):
public partial class MyView : UserControl // or whatever it is
{
public MyView(MyViewModel viewModel)
{
// Possibly ensure that viewModel is not null
InitializeComponent();
_myViewModel = viewModel;
this.AddHandler(System.Windows.Controls.Validation.ErrorEvent, new RoutedEventHandler(OnValidationRaised));
}
private MyViewModel _myViewModel;
private void OnValidationRaised(object sender, RoutedEventArgs e)
{
var args = (System.Windows.Controls.ValidationErrorEventArgs)e;
if (_myViewModel != null)
{
// Check if the error was caused by an exception
if (args.Error.RuleInError is ExceptionValidationRule)
{
// Add or remove the error from the ViewModel
if (args.Action == ValidationErrorEventAction.Added)
_myViewModel.AddUIValidationError();
else if (args.Action == ValidationErrorEventAction.Removed)
_myViewModel.RemoveUIValidationError();
}
}
}
}
在Command的CanExecute方法中,您將檢查ViewModel的_errorCount字段是否大於0,在這種情況下,應該禁用該命令。
請注意,您必須將ValidatesOnExceptions=True, NotifyOnValidationError=True
到綁定中,以便這可以工作。 例如:
<TextBox Text="{Binding Path=MyProperty, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />
編輯:
另一種方法,除了Riley提到的(這也很好,但要求你將模型中的每個整數屬性映射到ViewModel中的新字符串屬性)都使用ValidationRules。 您可以添加在解析和調用屬性setter之前檢查的ValidationRule
。 因此,您可以繼承ValidationRule並實現Validate方法,以確保可以將字符串解析為整數。 例:
public class IntegerValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
int number;
if(Int32.TryParse((string)value, out number) == false)
return new ValidationResult(false, "It is not a valid number");
return new ValidationResult(true, null);
}
}
然后,在您的視圖中定義名稱空間,其中定義了IntegerValidationRule:
<UserControl
...
xmlns:rules="clr-namespace:MyApplication.ValidationRules"
...>
並在綁定中使用規則:
<TextBox>
<TextBox.Text>
<Binding Path="MyProperty">
<Binding.ValidationRules>
<rules:IntegerValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
但無論如何,您需要為要驗證的每個非字符串類型創建類,我認為Binding語法現在看起來有點長。
問候
考慮從視圖模型而不是從視圖中調用命令。
private int _myProperty;
public int MyProperty
{
get
{
return _myProperty;
}
set
{
_myProperty = value;
// See if the value can be parsed to an int.
int potentialInt;
if(int.TryParse(_myProperty, out potentialInt))
{
// If it can, execute your command with any needed parameters.
yourCommand.Execute(_possibleParameter)
}
}
}
這將允許您處理用戶鍵入無法解析為整數的內容,並且只有當用戶鍵入的是整數時才會觸發該命令。
(我沒有測試這段代碼,但我認為它可能會有所幫助。)
我在網上找到的“最佳”解決方案在http://www.wpfsharp.com/2012/02/03/how-to-disable-a-button-on-textbox-validationerrors-in-wpf中有解釋。 /
簡而言之,驗證錯誤在View中處理,而不是在ViewModel中處理。 您不需要自己的ValidationRule。 只需在XAML中為按鈕添加樣式:
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="IsEnabled" Value="false" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=TextBox1, Path=(Validation.HasError)}" Value="false" />
<Condition Binding="{Binding ElementName=TextBox2, Path=(Validation.HasError)}" Value="false" />
<Setter Property="IsEnabled" Value="true" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
希望這可以幫助那些偶然發現這個問題的人(我知道這么多年后它不會對OP有所幫助)。
本文為您提供了非常深入的答案,並提供了源代碼: http : //karlshifflett.wordpress.com/2008/04/03/wpf-sample-series-handling-and-reporting-wpf-data-結合驗證-錯誤-和-例外/
我們甚至可以直接嘗試避免用戶在文本框中輸入任何字符
<TextBox Name="txtBox" PreviewTextInput="NumberValidationTextBox"/>
在 xaml.cs
private void NumberValidationTextBox(object sender, TextCompositionEventArgs e)
{
e.Handled = Regex.IsMatch(e.Text, "[^0-9]+");
}
我們可以檢查這個屬性的 Model,它在設置它之前檢查值以避免任何 null 或空值
private int _number;
public int Number
{
get => _number;
set
{
if(!string.IsNullOrEmpty(value.ToString())
_number = value;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.