2009-04-16 27 views
21

Tôi đã chấp nhận những gì dường như là cách chuẩn của hộp văn bản xác thực trong WPF bằng cách sử dụng giao diện IDataErrorInfo và kiểu như được hiển thị bên dưới. Tuy nhiên, làm cách nào tôi có thể vô hiệu hóa nút Lưu khi trang không hợp lệ? Điều này có được thực hiện bằng cách nào đó thông qua trình kích hoạt không?Vô hiệu hóa nút Lưu trong WPF nếu xác thực không thành công

Default Public ReadOnly Property Item(ByVal propertyName As String) As String Implements IDataErrorInfo.Item 
    Get 
     Dim valid As Boolean = True 
     If propertyName = "IncidentCategory" Then 
      valid = True 
      If Len(IncidentCategory) = 0 Then 
       valid = False 
      End If 
      If Not valid Then 
       Return "Incident category is required" 
      End If 
     End If 

     Return Nothing 

    End Get 
End Property 

<Style TargetType="{x:Type TextBox}"> 
    <Setter Property="Margin" Value="3" /> 
    <Setter Property="Height" Value="23" /> 
    <Setter Property="HorizontalAlignment" Value="Left" /> 
    <Setter Property="Validation.ErrorTemplate"> 
     <Setter.Value> 
      <ControlTemplate> 
       <DockPanel LastChildFill="True"> 
        <Border BorderBrush="Red" BorderThickness="1"> 
         <AdornedElementPlaceholder Name="MyAdorner" /> 
        </Border> 
       </DockPanel> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
    <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> 

Trả lời

37

Một vài điều:

Trước tiên, tôi muốn giới thiệu cách sử dụng RoutedCommand ApplicationCommands.Save để thực hiện việc xử lý các nút lưu.

Nếu bạn chưa xem mô hình Lệnh WPF, bạn có thể nhận được tin nhắn số here.

<Button Content="Save" Command="Save"> 

Bây giờ, để thực hiện các chức năng, bạn có thể thêm một lệnh ràng buộc vào Window/UserControl hoặc nút riêng của mình:

<Button.CommandBindings> 
     <CommandBinding Command="Save" 
         Executed="Save_Executed" CanExecute="Save_CanExecute"/> 
    </Button.CommandBindings> 
</Button> 

Thực hiện những trong mã đằng sau:

private void Save_Executed(object sender, ExecutedRoutedEventArgs e) 
{ 
} 

private void Save_CanExecute(object sender, CanExecuteRoutedEventArgs e) 
{ 
} 

Trong Save_CanExecute, đặt e.CanExecute dựa trên tính hợp lệ của ràng buộc trên hộp văn bản.

Nếu bạn muốn triển khai bằng mẫu thiết kế MVVM (Model-View-ViewModel), hãy xem bài đăng của Josh Smith trên CommandSinkBinding.

Một lưu ý cuối cùng: Nếu bạn muốn bật/tắt được cập nhật ngay sau khi giá trị trong TextBox được thay đổi, thiết lập UpdateSourceTrigger="PropertyChanged" trên các ràng buộc cho TextBox.

EDIT: Nếu bạn muốn xác thực/không hợp lệ dựa trên tất cả các ràng buộc trong điều khiển, dưới đây là một vài gợi ý.

1) Bạn đã triển khai IDataErrorInfo. Hãy thử triển khai thuộc tính IDataErrorInfo.Error sao cho nó trả về chuỗi không hợp lệ cho tất cả các thuộc tính mà bạn đang ràng buộc. Điều này sẽ chỉ hoạt động nếu toàn bộ điều khiển của bạn có ràng buộc với một đối tượng dữ liệu duy nhất. Đặt e.CanExecute = string.IsNullOrEmpty(data.Error);

2) Sử dụng phản ánh để nhận tất cả các công khai DependencyProperties tĩnh trên các điều khiển có liên quan. Sau đó, gọi BindingOperations.GetBindingExpression(relevantControl, DependencyProperty) trong vòng lặp trên mỗi thuộc tính để bạn có thể kiểm tra xác thực.

3) Trong hàm tạo, tạo thủ công một tập hợp tất cả các thuộc tính bị ràng buộc trên các điều khiển lồng nhau. Trong CanExecute, lặp qua bộ sưu tập này và xác thực mỗi kết hợp DependencyObject/DepencyProperty bằng cách sử dụng để nhận biểu thức và sau đó kiểm tra BindingExpression.HasError.

+1

Các công trình lớn cảm ơn nhiều. Một điều khác mặc dù. Tôi có thể kiểm tra các điều khiển riêng lẻ bằng mã sau Nếu Validation.GetHasError (myTextbox) Sau đó e.CanExecute = False Có cách nào để kiểm tra tính hợp lệ của tất cả các điều khiển thay vì riêng lẻ không? – Mitch

+0

Tôi đã chỉnh sửa để bao gồm một số ý tưởng về việc này. –

+2

+1 để sử dụng lệnh được đề xuất. Lệnh là những gì làm cho WPF bắt đầu thực sự bấm cho tôi. –

1

tôi đã tạo ra tài sản gắn liền chỉ cho việc này:

public static class DataErrorInfoHelper 
{ 
    public static object GetDataErrorInfo(ButtonBase obj) 
    { 
     return (object)obj.GetValue(DataErrorInfoProperty); 
    } 

    public static void SetDataErrorInfo(ButtonBase obj, object value) 
    { 
     obj.SetValue(DataErrorInfoProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for DataErrorInfo. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty DataErrorInfoProperty = 
     DependencyProperty.RegisterAttached("DataErrorInfo", typeof(object), typeof(DataErrorInfoHelper), new PropertyMetadata(null, OnDataErrorInfoChanged)); 

    private static void OnDataErrorInfoChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var button = d as ButtonBase; 

     if (button.Tag == null) 
      button.Tag = new DataErrorInfoContext { Button = button }; 

     var context = button.Tag as DataErrorInfoContext; 

     if(e.OldValue != null) 
     { 
      PropertyChangedEventManager.RemoveHandler(((INotifyPropertyChanged)e.OldValue), context.Handler, string.Empty); 
     } 

     var inotify = e.NewValue as INotifyPropertyChanged; 
     if (inotify != null) 
     { 
      PropertyChangedEventManager.AddHandler(inotify, context.Handler, string.Empty); 
      context.Handler(inotify, new PropertyChangedEventArgs(string.Empty)); 
     } 
    } 

    private class DataErrorInfoContext 
    { 
     public ButtonBase Button { get; set; } 

     public void Handler(object sender, PropertyChangedEventArgs e) 
     { 
      var dei = sender as IDataErrorInfo; 

      foreach (var property in dei.GetType().GetProperties()) 
      { 
       if (!string.IsNullOrEmpty(dei[property.Name])) 
       { 
        Button.IsEnabled = false; 
        return; 
       } 
      } 
      Button.IsEnabled = string.IsNullOrEmpty(dei.Error); 
     } 
    } 
} 

Tôi đang sử dụng nó như thế này trên hình thức của tôi:

<TextBlock Margin="2">e-mail:</TextBlock> 
<TextBox Margin="2" Text="{Binding Email, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/> 
<!-- other databindings---> 
<Button Margin="2" local:DataErrorInfoHelper.DataErrorInfo="{Binding}" Commands="{Binding SaveCommand}">Create account</Button> 
Các vấn đề liên quan