代码之家  ›  专栏  ›  技术社区  ›  ecathell

将IsDirty与ICommands一起使用

  •  0
  • ecathell  · 技术社区  · 14 年前

    我正在尝试使用IsDirty标志来控制对象编辑期间的CanExecute和导航控件。

    问题是为了让它工作,我想我必须使用onPropertyChanged作为我的IsDirty方法,这样我的控件才能得到更改通知。(我想在我的对象为Dirty时禁用一些控件)不幸的是,我得到了一个讨厌的堆栈溢出,因为它螺旋式地进入了一个可怕的IsDirty循环…呵呵。。

    有人知道如何实现这样的东西吗?

    这是我的解决方案

    :在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
    

    :在从ViewModelBase派生的EditViewModelBase中。

    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
    

    ●在我的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
    
    3 回复  |  直到 14 年前
        1
  •  0
  •   Jose    14 年前

    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);
    }
    

    或者,如果CanSave仅引用IsDirty,则可以将ICommand设置为:

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

    只要 RelayCommand CommandManager.RequerySuggested 对于 CanExecuteChanged CanSave

    这是很重要的一点,因为没有 CommandManager.RequerySuggested建议 WPF不知道如何更新UI。这可能会变得有点昂贵,因为每次在viewmodel中更改任何值时,您的所有 中继命令 我们被重新询问。但是,只要您的CanExecute谓词是一个简单的计算,就可以忽略不计,也就是说,如果您在CanExecute谓词中调用数据库或web服务,可能会出现一些严重的性能问题:)

        2
  •  1
  •   John Bowen    14 年前

    避免堆栈溢出的最简单方法是向IsDirty属性设置程序添加一个guard子句:

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

    不幸的是,如果您尝试设置IsDirty=false,您仍然会遇到问题,因为它将通过PropertyChanged方法重置为true。为了避免这种情况,您应该检查该方法中的属性名,如果更改的属性名是“IsDirty”,则跳过IsDirty的设置。

        3
  •  0
  •   Phil Sandler    14 年前

    你不需要通知IsDirty已经改变了。只要将它设为一个普通属性或字段,它就可以正常工作(并且没有无限循环)。

    这是假设您正在使用RelayCommand,而每个人似乎都在使用它(有充分的理由) Josh Smith's article