2010-07-09 18 views
0

J'essaie d'utiliser un indicateur IsDirty pour contrôler les contrôles CanExecute et de navigation pendant une modification d'objet. Le problème est que pour que cela fonctionne je pense que je dois utiliser onPropertyChanged pour ma méthode IsDirty afin que mes contrôles obtiennent une notification de changement (je veux que certains contrôles soient désactivés quand mon objet IsDirty) Malheureusement, je reçois un vilain stackoverflow parce qu'il spirale dans une boucle horrible de IsDirty ... hehe ..Utilisation de IsDirty avec des ICommands

Quelqu'un at-il été en mesure de faire quelque chose de similaire à ce travail? Tout ce que je fais est de mettre IsDirty à true dans ma méthode OnPropertyChanged. Ensuite, dans mes méthodes canExecute, je vois si elle est définie sur true, mais ensuite sur mes contrôles, j'ai besoin de Databind ... qui cause tout le problème. Est-ce que quelqu'un sait comment implémenter quelque chose comme ça?

ceci est ma solution

:: En ViewModelBase

Private _isdirty As Boolean = False 
     Protected Property IsDirty As Boolean 
      Get 
       Return _isdirty 
      End Get 
      Set(ByVal value As Boolean) 
       If _isdirty = Not value Then 
        _isdirty = value 
        If _isdirty = True Then 
         DisableNavigation() 
        Else 
         EnableNavigation() 
        End If 
       End If 
      End Set 
     End Property 

Private _haschanges As Boolean 
     Public Property HasChanges As Boolean 
      Get 
       Return _haschanges 
      End Get 
      Set(ByVal value As Boolean) 
       If value = Not _haschanges Then 
        _haschanges = value 
        OnPropertyChanged("HasChanges") 
       End If 
      End Set 
     End Property 



Protected Sub EnableNavigation() 
      'Keep from firing multiple onPropertyChanged events 
      If HasChanges = True Then 
       HasChanges = False 
      End If 

      GetEvent(Of DisableNavigationEvent).Publish(False) 

     End Sub 

     Protected Sub DisableNavigation() 
      'Keep from firing multiple onPropertyChanged events 
      If HasChanges = False Then 
       HasChanges = True 
      End If 
      GetEvent(Of DisableNavigationEvent).Publish(True) 

     End Sub 

:: En EditViewModelBase DÉRIVÉS de ViewModelBase.

Protected Overrides Sub OnPropertyChanged(ByVal strPropertyName As String) 
      MyBase.OnPropertyChanged(strPropertyName) 

      If SetsIsDirty(strPropertyName) Then 
       If isLoading = False Then 

        IsDirty = True 
       Else 
        IsDirty = False 

       End If 
      End If 



     End Sub 
     ''' <summary> 
     ''' Helps prevent stackoverflows by filtering what gets checked for isDirty 
     ''' </summary> 
     ''' <param name="str"></param> 
     ''' <returns></returns> 
     ''' <remarks></remarks> 
     Protected Function SetsIsDirty(ByVal str As String) As Boolean 

      If str = "CurrentVisualState" Then Return False 
      If str = "TabsEnabled" Then Return False 
      If str = "IsLoading" Then Return False 
      If str = "EnableOfficeSelection" Then Return False 

      Return True 

     End Function 

:: Dans mon viewmodel

Public ReadOnly Property SaveCommand() As ICommand 
      Get 
       If _cmdSave Is Nothing Then 
        _cmdSave = New RelayCommand(Of DoctorOffice)(AddressOf SaveExecute, Function() CanSaveExecute()) 
       End If 
       Return _cmdSave 
      End Get 
     End Property 

Private Function CanSaveExecute() As Boolean 
      'if the object is dirty you want to be able to save it. 
      Return IsDirty 

     End Function 

     Private Sub SaveExecute(ByVal param As DoctorOffice) 
      BeginWait() 
      GetService(Of Services.IDoctorOfficesService).Update(SelectedDoctorOffice, False) 
      EndWait() 

     End Sub 
+0

Pouvez-vous coller l'implémentation de votre propriété IsDirty et des gestionnaires d'événements Execute/CanExecute? –

Répondre

0

ont juste votre prédicat CanExecute pour vous ICommand d'inclure la propriété IsDirty

par exemple

public class MyViewModel 
{ 
    public CanSave { get { return IsDirty;}} 
    public void Save(object parameter) 
    { 
    //Do stuff here 
    } 

    public ICommand SaveCommand = new RelayCommand(() => this.Save,() => this.CanSave); 
} 

ou si CANSAVE est que vous pouvez IsDirty consultait que définissez votre ICommand être ceci:

public ICommand SaveCommand = new RelayCommand(() => this.Save,() => this.IsDirty); 

Tant que RelayCommand utilise CommandManager.RequerySuggested pour l'événement CanExecuteChanged le prédicat CanSave sera requeried à tout moment une valeur de liaison changements dans le ViewModel.

Et c'est un gros point car sans CommandManager.RequerySuggested WPF ne saura pas mettre à jour l'interface utilisateur. Cela peut devenir un peu cher parce que chaque fois que la valeur est modifiée dans le viewmodel, tous vos RelayCommand sont demandés. Mais il est probablement négligeable tant que votre prédicat CanExecute est un calcul simple, c'est-à-direSi vous appelez une base de données ou un service Web dans votre prédicat CanExecute, vous risquez de rencontrer de sérieux problèmes de performances :)

+0

je vais marquer le tien correct parce que c'était le plus proche de ce que j'avais besoin de faire et je n'ai pas vraiment eu assez de profondeur au début ... – ecathell

1

La façon la plus simple d'éviter le débordement de la pile est à aa clause de garde à votre IsDirty poseur de propriété:

public bool IsDirty 
{ 
    get { return _isDirty; } 
    set 
    { 
     if (_isDirty == value) 
      return; 
     _isDirty = value; 
     NotifyPropertyChanged("IsDirty"); 
    } 
} 

Malheureusement juste faire ce que vous Vous aurez toujours un problème si vous essayez de définir IsDirty = false car il sera réinitialisé à true par votre méthode PropertyChanged. Pour éviter cela, vous devriez vérifier le nom de la propriété dans cette méthode et ignorer le paramètre IsDirty si le nom de la propriété modifiée est "IsDirty".

+0

Je l'avais essayé dong, sauf la déclaration de garde dans le setter ... mauvais essayer aussi. J'ai plusieurs autres booléens «d'état» que j'ai mis en place une méthode qui est vérifiée et puis place le sale ... ... post un peu de code une fois que je l'ai migré à la maison du travail. – ecathell

0

Vous n'avez pas besoin de notifier que IsDirty a changé. Faites-en une simple propriété ou un champ et cela devrait fonctionner correctement (et pas de boucle infinie).

Cela suppose que vous utilisez la RelayCommand que tout le monde semble utiliser (pour une bonne raison) de Josh Smith's article dans MSDN Magazine.

+0

si vous ne relancez pas notifyproperty a changé vos contrôles standard ne savent pas qu'ils ont besoin de rafraîchir. – ecathell

+0

Ah, raté la partie sur la désactivation des contrôles - pensé qu'il s'agissait de CanExecute. –