2011-12-21 5 views
2

내가 전에 한 것은 데이터 객체의 전체 복사본을 만든 다음 두 객체간에 차이가 있는지 비교하기 위해 반사기를 사용하는 일반 비교 메소드를 작성하는 것입니다.데이터가 변경된 경우에만 사용자가 저장하도록 허용하는 더 좋은 방법은 무엇입니까?

SaveButton이 있고 TextBoxA가 ViewModel.PropertyA로 바인드 된 경우 초기 PropertyA는 "123"입니다.

사용자가 TextBoxA에서 "1234"를 입력하면 PropertyA set 메서드는 compare 메서드를 실행하여 차이점을 찾습니다. 저장 버튼을 활성화하십시오.

하지만 사용자가 텍스트 "1234"를 다시 "123"으로 변경하면 저장 버튼이 다시 비활성화됩니다.

1 년이 지난 지금, 더 좋은 방법이나 쉬운 방법이 있습니까? 즉, 이런 종류의 작업을 수행 할 프레임 워크가 있습니까? 그래서 객체를 딥 카피하기위한 코드를 작성하지 않고 직접 비교 메소드를 작성합니까?


내가 가진 실제 UI

는 따라서 나는 전체 개체를 복제에 대한 깊은 복사 방법을 쓴 이유 등 날짜 시간, 컬렉션을 편집 고객 정보에 대한 UI했다, 단지 텍스트 상자 유형을 포함하는 간단하지 않았다.

+0

UI가 영리해야합니까? 저장 버튼을 활성화하고 활성화 된 상태로 변경하는 것이 어떻습니까? 사용자가 값을 다시 변경하면 여전히 변경된 것입니다. 비즈니스 응용 프로그램에 따라 즉시 변경된 경우에도 "변경된 내용"을 추적 할 가치가 있습니다. 감사 로그는 아무 것도 변경하지 않더라도 "이 레코드가 다시 명시 적으로 User123에 저장되었습니다"라고 말할 수 있습니다. 내 이전 관리자가 준 요구 사항 중 하나였던 – David

+0

. 나는 그 때까지는 생각하지 않았지만, 불필요한 트래픽을 원하지 않는다고 생각한다. 컴퓨터 지식이없는 일부 사용자는 텍스트를 변경 한 다음 다시 변경하고 다시 저장하기 때문에 (항상 필요하다고 생각한다. 어쨌든 저장 버튼을 클릭하십시오). 그가 내게 말한 이유 중 하나는 사용자가 이미 저장했다는 것을 알았 기 때문입니다. –

답변

0

질문에 MVVM 태그가 지정되어 있기 때문에 View Model의 이러한 속성이 어떻게 든 PropertyChanged 이벤트를 발생시키고 있다고 가정합니다.

하나의 방법이 있습니다. ViewModel의 PropertyChanged 이벤트에 대한 이벤트 핸들러를 작성하십시오. 특성이 변경 될 때만 원래 값을 개인 Dictionary<string, string>에 저장하십시오. 따라서 누군가 편집을 할 때를 대비하여 전체 객체를 복사 할 필요가 없습니다. 속성이 사전에 이미 있으면 원래 값으로 다시 변경되었는지 쉽게 확인할 수 있습니다.

편집 : 오, 나는 PropertyChangedEventArgs에 새로운 값과 오래된 값이 포함되어 있다고 생각했지만 그렇지 않습니다. 따라서 이렇게하려면 각 속성의 이전 값과 새 값을 평가할 수있는 View Model의 속성 setter 내에 추가 메서드 호출을 추가해야합니다.

저장 단추를 사용하거나 사용하지 않도록 설정하기 쉽게하려면 저장 단추의 enabled 속성을 바인딩 할보기 모델에 bool 속성이 있어야합니다.

새 값이 원래 값과 일치 할 때마다 항목이 사전에서 제거되면 사전에 항목이 있으면 Save button enabled 속성이 true를 반환 할 수 있습니다.

편집 2 : 컬렉션 유형의 경우 View 모델을보기 모델에 ObservableCollection 속성으로 바인딩해야합니다. Collection changed 이벤트는 이전 항목과 새 항목의 목록을 제공하므로 해당 이벤트 핸들러 내에서 변경 사항을 추적하는 것이 매우 쉬워야합니다.

+0

'Dictionary '? 그래서 그의 모델에는 문자열 속성 만 있다고 가정하고 있습니까? 어쩌면 숫자 필드 나 체크 박스 또는 객체와 같은 기타 문자열이 아니기 때문에 –

+0

개인적으로 문자열을 사용하여 값을 표현할 수 있습니다. 원하는 경우 'Dictionary '를 자유롭게 작성하십시오. 내 개념에서는 값이 사전에서 모델 객체로 다시 복사되지 않으므로 속성 값에서 문자열로의 편도 변환이 가장 적합합니다. – CoderDennis

+0

@Dennis Palmer 이것은 좋은 생각 인 것 같습니다.이 방법은 전체 데이터 객체를 복제하지 않고 차이를 비교하는 것이 더 빠릅니다. 적어도 지금은 복제 방법을 쓰지 않습니다! 감사! :) –

0

ViewModel이 자신의 개체이고이를 수정할 수있는 경우 ICloneable 인터페이스를 구현하여 복사본을 만들 수 있습니다.

다음으로 IComparable 인터페이스를 구현하십시오. 여기서 T는 뷰 모델입니다. 그래서 쉽게 비교할 수 있습니다

그럼 당신은 모든 속성에 대해 PropertyChanged 이벤트를 만들어야하고, 하나가 해고되면 비교할 수 있습니다.

나는 거의 당신이 이미 지금 가지고있는 것과 같은 그 추측하지만 ICloneableIComparable에 따라 논리를 작성하는 경우 적어도 당신은 단지 그것을 쓰기 한 번

편집이 : 그리고 당신이 경우에 간단하게 할 자체 비교 메소드를 작성하고 싶지 않은 경우 this post과 같은 모든 속성을 자동으로 비교하는 코드 단편이 있습니다. 그러나, 이와 같은 것을 사용하는 것은 자신 만의 compare 함수를 작성하는 것보다 훨씬 느립니다 (성능 현명한).

+0

제가 언급 한 사실을 잊어 버린 것 같아요. 제가 작성한 딥 복사 방법은 어떤 객체 (불완전하고 일부 속성 롤을 복사하지 않았습니다)에 딥 복사에 사용할 수있는 일반적인 방법이었습니다. 비교 방법으로도 모든 유형의 객체를 깊이 비교할 수있는 일반적인 방법. –

+0

그럼 내 대답은 무시해도 될 것 같아. 사용자가'ViewModel.Textbox.Text'와 같은 것을 설정하도록 허용합니까? 아니면 모든 것에 세터가 있습니까? (그래서 이벤트를 추가하면 [뭔가가 변경되면 감지 할 수 있습니다] –

+0

ViewModel의 모든 속성에는 setters가 있으며 비교 메서드를 발생시켜 저장 단추에 바인딩 된 CanSave 속성을 변경합니다.난 정말 궁금해. 이런 종류의 일을 할 수있는 그런 틀이 없니? –

0

상태 관리를 속성 변경 알림과 함께 사용하려는 것처럼 들립니다. 국가 관리는 당신이 원하는 것을 어떻게 할 것인가에 달려 있습니다. 의미있는 몇 가지 개념은 원래의 속성 (속성 이름)을 기본 필드 (속성 값)에 매핑하는 개체의 백업 복사본 또는 Dictionary<string, object>을 사용하는 것입니다.

변경 사항이 있는지 확인하려면 INotifyPropertyChanged 인터페이스를 사용합니다. 이렇게하면 상태 관리 및 알림을 클래스 내부에 보관할 수 있습니다. 부울 배열/사전 (Dict<string, bool>)을 설정하는 OnPropertyChanged (문자열 propName, 객체 propValue)라는 래퍼를 구현하면 속성이 변경되면 HasChanges 속성이 true를 반환하고 변경 사항이 있는지 여부를 설정할 수 있습니다. 예 클래스 : 단순 위해서

public class TestClass : INotifyPropertyChanged 
{ 
    private Dictionary<string, object> BackingStore = new Dictionary<string,object>(); 
    private Dictionary<string, bool> Changes = new Dictionary<string, bool>(); 
    private string _testString; 
    public string TestString 
    { 
     get { return _testString; } 
     set { _testString = value; OnPropertyChanged("TestString", value); } 
    } 

    private bool HasChanges { get; set; } 
    public event PropertyChangedEventHandler PropertyChanged; 

    public TestClass(string value) 
    { 
     _testString = value; 
     SaveValues(); 
    } 

    public void SaveValues() 
    { 
     // Expensive, to use reflection, especially if LOTS of objects are going to be used. 
     // You can use straight properties here if you want, this is just the lazy mans way. 
     this.GetType().GetProperties().ToList().ForEach(tProp => { BackingStore[tProp.Name] = tProp.GetValue(this, null); Changes[tProp.Name] = false; }); 
     HasChanges = false; 

    } 

    public void RevertValues() 
    { 
     // Again, you can use straight properties here if you want. Since this is using Property setters, will take care of Changes dictionary. 
     this.GetType().GetProperties().ToList().ForEach(tProp => tProp.SetValue(this, BackingStore[tProp.Name], null)); 
     HasChanges = false; 
    } 

    private void OnPropertyChanged(string propName, object propValue) 
    { 
     // If you have any object types, make sure Equals is properly defined to check for correct uniqueness. 
     Changes[propName] = BackingStore[propName].Equals(propValue); 
     HasChanges = Changes.Values.Any(tr => tr); 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propName)); 
    } 
} 

, 난 그냥 저장 SaveValues ​​/ RevertValues를 사용/변경 사항을 취소. 그러나 이들을 사용하여 쉽게 IEditableObject 인터페이스 (BeginEdit, CancelEdit, EndEdit)를 구현할 수 있습니다. 그런 다음 PropertyChanged 이벤트는 객체가 바인딩되는 양식 (또는 단일 인스턴스 만 구독해야하는 기본 BindingList)에 가입 할 수 있습니다.이 양식은 HasChanges 플래그를 확인하고 적절한 상태를 설정합니다. 형태.

관련 문제