2015-05-13 18 views
9

mi pare di aver letto già tutti gli articoli relativi, ma non di loro aiutare ..convalida WPF- evento di errore non si attiva

im cercando di abilitare/disabilitare un pulsante di salvataggio del datagrid dall'errore dallo Stato, ma con nessun successo.

questo è il mio codice:

contractor:

AddHandler(Validation.ErrorEvent, new RoutedEventHandler(OnErrorEvent)); 

XAML:

codice
<Page 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:col="clr-namespace:System.Collections;assembly=mscorlib" 
xmlns:local="clr-namespace:Metsuka_APP" x:Class="Metsuka_APP.MichlolimManagment" 
    mc:Ignorable="d" 
    d:DesignHeight="500" d:DesignWidth="500" 
Title="MichlolimManagment" 
x:Name="Michlolim_Managment" Validation.Error="Michlolim_Managment_Error"> 
<Page.Resources> 

<DataGrid x:Name="AGAFIMDataGrid" VerticalAlignment="Center" RowEditEnding="rowEditEnding" Margin="10" FlowDirection="RightToLeft" Height="340" 
    AutoGenerateColumns="False" EnableRowVirtualization="True" 
        ItemsSource="{Binding Source={StaticResource aGAFIMViewSource}}" Grid.Row="1" 
        RowDetailsVisibilityMode="VisibleWhenSelected" 
       ScrollViewer.CanContentScroll="True" 
       ScrollViewer.VerticalScrollBarVisibility="Auto" 
       HorizontalGridLinesBrush="Silver" 
       VerticalGridLinesBrush="Silver"> 
      <DataGrid.Resources> 
       <Style x:Key="errorStyle" TargetType="{x:Type TextBox}"> 
        <Setter Property="Padding" Value="-2"/> 
        <Style.Triggers> 
         <Trigger Property="Validation.HasError" Value="True"> 
          <Setter Property="Background" Value="Red"/> 
          <Setter Property="ToolTip" 
      Value="{Binding RelativeSource={RelativeSource Self}, 
      Path=(Validation.Errors)[0].ErrorContent}"/> 
         </Trigger> 
        </Style.Triggers> 
       </Style> 
      </DataGrid.Resources> 
      <DataGrid.Columns> 
       <DataGridTextColumn x:Name="agaf_nameColumn" Header="name" Width="*"> 
        <DataGridTextColumn.Binding> 
         <Binding Path="agaf_name" NotifyOnValidationError="True" > 
          <Binding.ValidationRules> 
          <local:MichlolimValidationRule ValidationStep="UpdatedValue"/> 
         </Binding.ValidationRules> 
        </Binding> 
         </DataGridTextColumn.Binding> 
       </DataGridTextColumn> 
      </DataGrid.Columns> 
      <DataGrid.RowValidationErrorTemplate> 
       <ControlTemplate> 
        <Grid Margin="0,-2,0,-2" 
      ToolTip="{Binding RelativeSource={RelativeSource 
      FindAncestor, AncestorType={x:Type DataGridRow}}, 
      Path=(Validation.Errors)[0].ErrorContent}"> 
         <Ellipse StrokeThickness="0" Fill="Red" 
       Width="{TemplateBinding FontSize}" 
       Height="{TemplateBinding FontSize}" /> 
         <TextBlock Text="!" FontSize="{TemplateBinding FontSize}" 
       FontWeight="Bold" Foreground="White" 
       HorizontalAlignment="Center" /> 
        </Grid> 
       </ControlTemplate> 
      </DataGrid.RowValidationErrorTemplate> 
     </DataGrid> 

dietro:

private int errorCount; 

    private void OnErrorEvent(object sender, RoutedEventArgs e) 
    { 
     var validationEventArgs = e as ValidationErrorEventArgs; 
     if (validationEventArgs == null) 
      throw new Exception("Unexpected event args"); 
     switch (validationEventArgs.Action) 
     { 
      case ValidationErrorEventAction.Added: 
       { 
        errorCount++; break; 
       } 
      case ValidationErrorEventAction.Removed: 
       { 
        errorCount--; break; 
       } 
      default: 
       { 
        throw new Exception("Unknown action"); 
       } 
     } 
     btnSavePop.IsEnabled = errorCount == 0; 
    } 

ma il "OnErrorEvent" mai fires- alcuna idea w hy?

+0

È possibile inserire il codice per i modelli visualizzati in DataGrid? Principalmente la proprietà agaf_name. – Bijington

+0

basato su DB: che codice esattamente vuoi vedere? – DasDas

+0

Volevo vedere come è definita la proprietà per vedere come funzionerebbe il binding. Come Adi ha appena suggerito in risposta, è necessario implementare IDataErrorInfo ma è necessario anche associare a una proprietà di dipendenza o utilizzare INotifyPropertyChanged sulla classe che è associata a – Bijington

risposta

2

L'attributo

Validation.Error="Michlolim_Managment_Error" 

in XAML definisce già un gestore per l'evento di errore sul piano della finestra, tuttavia, a un metodo che non è definito nel codice dietro il frammento. La tua chiamata AddHandler sembra ok, ma, a seconda di dove si trova nel costruttore, potrebbe essere sovrascritta dalla definizione del gestore di eventi XAML.

Probabilmente non correlati, ma si potrebbe desiderare di cambiare

(Validation.Errors)[0].ErrorContent 

a

(Validation.Errors)/ErrorContent 

nei vostri attacchi ToolTip, dal momento che gli ex cause errori vincolanti se non ci sono errori. Sfortunatamente, è ancora contenuto negli esempi di documentazione ...

2

È necessario impostare NotifyOnValidationError="True" sui binding, altrimenti l'evento non verrà generato. Raccomanderei di utilizzare le interfacce IDataErrorInfo o INotifyDataErrorInfo per un approccio di gestione degli errori MVVM.

+0

ho già quella riga nel mio codice! btw non sta utilizzando MVVM – DasDas

3

Prova a creare una classe come la seguente:

public class AgafDescriptor : INotifyPropertyChanged, IDataErrorInfo 
{ 
    private string _name; 

    public string Name 
    { 
     get 
     { 
      return _name; 
     } 
     set 
     { 
      if (_name != value) 
      { 
       _name = value; 

       RaisePropertyChanged(x => x.Name); 
      } 
     } 
    } 

    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected void RaisePropertyChanged<T>(Expression<Func<AgafDescriptor, T>> propertyExpression) 
    { 
     PropertyChangedEventHandler localPropertyChanged = this.PropertyChanged as PropertyChangedEventHandler; 

     if ((localPropertyChanged != null) && (propertyExpression != null)) 
     { 
      MemberExpression body = propertyExpression.Body as MemberExpression; 

      if (body != null) 
      { 
       localPropertyChanged(this, new PropertyChangedEventArgs(body.Member.Name)); 
      } 
     } 
    } 

    #endregion 

    #region IDataErrorInfo Members 

    // Does nothing in WPF. 
    public string Error 
    { 
     get { return null; } 
    } 

    public string this[string columnName] 
    { 
     get 
     { 
      string returnVal = null; 

      if (string.Equals("Name", columnName, StringComparison.Ordinal)) 
      { 
       if (string.IsNullOrWhiteSpace(Name)) 
       { 
        returnVal = "A name must be supplied."; 
       } 
      } 

      return returnVal; 
     } 
    } 

    #endregion 
} 

Ciò fornirà un errore ogni volta che c'è un cambiamento alla proprietà Name. Si prega di notare che se si desidera attivare nuovi controlli di convalida senza modificare la proprietà è sufficiente chiamare:

RaisePropertyChanged(x => x.Name); 

Sarà quindi necessario cambiare il vostro legame con qualcosa di simile:

<DataGridTextColumn x:Name="agaf_nameColumn" Header="name" Width="*" Binding="{Binding Name, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, NotifyOnValidationError=True}"/> 

Nota si vuole caricare i dati dal DB e creare un descrittore per ciascun elemento che si desidera visualizzare in DataGrid.

Il motivo dietro perché non si è visto l'evento di essere licenziato:

Non stanno alzando eventi di modifica di proprietà (INotifyPropertyChanged o attraverso un DependencyProperty), pertanto l'interfaccia utente non riceveranno aggiornamenti e l'evento non verrà licenziato perché non ha ricevuto un aggiornamento per poi eseguire la convalida. Associando direttamente al tuo DB, non stai sollevando gli eventi di modifica delle proprietà. Si può vedere che la proprietà Name ho suggerito nella mia risposta solleva la proprietà modificata evento

+0

e devo creare una classe del genere per ogni colonna che devo controllare? – DasDas

+0

No dovresti avere 1 proprietà per ogni colonna che vuoi controllare. – Bijington

+0

ma che non risponde alla mia domanda perché l'evento non è stato sparato :( – DasDas

1

Dal mio esempio del codice penso che manchi specificare UpdateSourceTrigger = "PropertyChanged" o UpdateSourceTrigger = "LostFocus" sul DataGridTextColumn in DataGrid invece di utilizzare il comportamento predefinito del binding di DataGrids.

Ciò presuppone che le mie supposizioni siano corrette vedi in basso.

Il codice fa sì che OnErrorEvent al fuoco se cambio:

<DataGridTextColumn.Binding> 
    <Binding Path="agaf_name" NotifyOnValidationError="True" > 
    ... 

Per includere UpdateSourceTrigger per PropertyChanged o LostFocus in questo modo:

<DataGridTextColumn.Binding> 
    <Binding Path="agaf_name" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged" > 
    .... 

enter image description here

Ipotesi - Per la vostra ValidationRule per testare l'ho fatto restituire sempre false (vedi sotto). E per l'origine dell'elemento di test lego a un valore stringa nella proprietà 'agaf_name'.

public class MichlolimValidationRule : ValidationRule 
{ 
    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo) 
    { 
     return new ValidationResult(false, "bad"); 
    } 
}