1

LoadOperation의 엔터티를 사용하여 내 View Model에서 CollectionViewSource의 소스가되는 IEnumerable을 반환하는 응용 프로그램을 작성했습니다. 이 접근법에 잠재적 인 함정을 발견했습니다. Silverlight 클라이언트에 엔티티를 추가 할 때 New Entity를 제출 한 다음 다시로드하거나 바인딩 할 항목의 별도 컬렉션을 유지하지 않는 한 엔티티를 볼 수 없습니다. - 나도 같은에서 DomainContext과 ObservableCollection에 모두에 추가 할 수있는이 방법MVVM 및 RIA 서비스를 사용하여 다른 바인딩 접근 방식에 대한 단점/단점

  1. 내 뷰 모델의 CollectionViewSource 속성의 소스로 사용하기 위해 ObservableCollection에 추가 : 정말 내 옵션은 다음과 같이 표시되는 내용

    컬렉션을 동기화 된 상태로 유지해야합니다.

  2. 바인딩을 EntitySet으로 직접 변경하고 필터링 이벤트 처리기를 추가하여 CollectionViewSource에서 필터링을 제공하십시오.

각 사용자의 장단점에 대한 도움말이나 의견이 있으면 큰 감사 드리겠습니다. 특히, 하나 또는 다른 것을 선호하여 성능 및/또는 프로그래밍 혜택이 있다면 궁금합니다.

답변

1

한 번에 하나의 접근 방식을 사용하고 있습니다. 첫 번째로, 나는 이것을 dicuss에 대한 참조 포인트를 보여줄 것이고, 나는 각 방법론을 지원하는 데 필요한 다양한 변화를 강조 할 것이다.

내 데모의 기초는 리소스의 단일 엔터티를 반환하는 인증 된 단일 도메인 서비스입니다. SelectedResource를 보유하기위한 4 개의 명령 (저장, 실행 취소, 추가 및 삭제)과 컬렉션 및 속성을 표시합니다.

2 다른 클래스가이 인터페이스를 구현합니다 (블렌딩의 경우 1, 프로덕션의 경우 1). 제작은 여기에서 논의 할 유일한 것입니다. GetMyResources 기능의 동작 (lo.Entities)주의 :

public class WorkProvider 
{ 
    static WorkContext workContext; 
    public WorkProvider() 
    { 
     if (workContext == null) 
      workContext = new WorkContext(); 
    } 
    public void AddResource(Resource resource) 
    { 
     workContext.Resources.Add(resource); 
    } 
    public void DelResource(Resource resource) 
    { 
     workContext.Resources.Remove(resource); 
    } 
    public void UndoChanges() 
    { 
     workContext.RejectChanges(); 
    } 
    public void SaveChanges(Action action) 
    { 
     workContext.SubmitChanges(so => 
      { 
       if (so.HasError) 
        // Handle Error 
        throw so.Error; 
       else 
        action(); 
      }, null); 
    } 
    public void GetMyResources(Action<IEnumerable<Resource>> action) 
    { 
     var query = workContext.GetResourcesQuery() 
      .Where(r => r.UserName == WebContext.Current.User.Name); 
     workContext.Load(query, LoadBehavior.MergeIntoCurrent, lo => 
      { 
       if (lo.HasError) 
        // Handle Error 
        throw lo.Error; 
       else 
        action(lo.Entities); 
      }, null); 
    } 
} 

뷰 모델에서를, 나는 다음과 같은 구현을 가지고 :

public class HomeViewModel : ViewModelBase 
{ 
    WorkProvider workProvider; 
    public HomeViewModel() 
    { 
     workProvider = new WorkProvider(); 
    } 

    // _Source is required when returning IEnumerable<T> 
    ObservableCollection<Resource> _Source; 
    public CollectionViewSource Resources { get; private set; } 
    void setupCollections() 
    { 
     Resources = new CollectionViewSource(); 
     using (Resources.DeferRefresh()) 
     { 
      _Source = new ObservableCollection<Resource>(); 
      Resources.Source = _Source; 
      Resources.GroupDescriptions.Add(new PropertyGroupDescription("Title")); 
      Resources.SortDescriptions.Add(new SortDescription("Title", ListSortDirection.Ascending)); 
      Resources.SortDescriptions.Add(new SortDescription("Rate", ListSortDirection.Ascending)); 
     } 
    } 
    void loadMyResources() 
    { 
     workProvider.GetMyResources(results => 
      { 
       using (Resources.DeferRefresh()) 
       { 
        // This is required when returning IEnumerable<T> 
        _Source.Clear(); 
        foreach (var result in results) 
        { 
         if (!_Source.Contains(result)) 
          _Source.Add(result); 
        } 
       } 
      }); 
    } 
    Resource _SelectedResource; 
    public Resource SelectedResource 
    { 
     get { return _SelectedResource; } 
     set 
     { 
      if (_SelectedResource != value) 
      { 
       _SelectedResource = value; 
       RaisePropertyChanged("SelectedResource"); 
      } 
     } 
    } 

    public RelayCommand CmdSave { get; private set; } 
    public RelayCommand CmdUndo { get; private set; } 
    public RelayCommand CmdAdd { get; private set; } 
    public RelayCommand CmdDelete { get; private set; } 
    void setupCommands() 
    { 
     CmdSave = new RelayCommand(() => 
      { 
       workProvider.SaveChanges(() => 
        { 
         DispatcherHelper.CheckBeginInvokeOnUI(() => 
          { 
           System.Windows.MessageBox.Show("Saved"); 
          }); 
        }); 
      }); 
     CmdUndo = new RelayCommand(() => 
      { 
       workProvider.UndoChanges(); 
       // This is required when returning IEnumerable<T> 
       loadMyResources(); 
      }); 
     CmdAdd = new RelayCommand(() => 
      { 
       Resource newResource = new Resource() 
       { 
        ResourceID = Guid.NewGuid(), 
        Rate = 125, 
        Title = "Staff", 
        UserName = "jsmith" 
       }; 
       // This is required when returning IEnumerable<T> 
       _Source.Add(newResource); 
       workProvider.AddResource(newResource); 
      }); 
     CmdDelete = new RelayCommand(() => 
     { 
      // This is required when returning IEnumerable<T> 
      _Source.Remove(_SelectedResource); 
      workProvider.DelResource(_SelectedResource); 
     }); 
    } 
} 

다음과 같이 WorkProvider 클래스를 변경 포함 할 대체 방법 (통지 반환되는 행동 (workContext.Resources) :

public void GetMyResources(Action<IEnumerable<Resource>> action) 
    { 
     var query = workContext.GetResourcesQuery() 
      .Where(r => r.UserName == WebContext.Current.User.Name); 
     workContext.Load(query, LoadBehavior.MergeIntoCurrent, lo => 
      { 
       if (lo.HasError) 
        // Handle Error 
        throw lo.Error; 
       else 
        // Notice Changed Enumeration 
        action(workContext.Resources); 
      }, null); 
    } 

그리고 뷰 모델에 대한 변경 사항은 다음과 같이합니다 (_Source ObservableCollectio의 제거를 알 수 있습니다 N)

public class HomeViewModel : ViewModelBase 
{ 
    WorkProvider workProvider; 
    public HomeViewModel() 
    { 
     workProvider = new WorkProvider(); 
    } 

    public CollectionViewSource Resources { get; private set; } 
    void setupCollections() 
    { 
     Resources = new CollectionViewSource(); 
     using (Resources.DeferRefresh()) 
     { 
      Resources.Filter += (s,a) => 
       { 
        a.Accepted = false; 
        if (s is Resource) 
        { 
         Resource res = s as Resource; 
         if (res.UserName == WebContext.Current.User.Name) 
          a.Accepted = true; 
        } 
       }; 
      Resources.GroupDescriptions.Add(new PropertyGroupDescription("Title")); 
      Resources.SortDescriptions.Add(new SortDescription("Title", ListSortDirection.Ascending)); 
      Resources.SortDescriptions.Add(new SortDescription("Rate", ListSortDirection.Ascending)); 
     } 
    } 
    void loadMyResources() 
    { 
     workProvider.GetMyResources(results => 
      { 
       using (Resources.DeferRefresh()) 
       { 
        Resources.Source = results; 
       } 
      }); 
    } 
    Resource _SelectedResource; 
    public Resource SelectedResource 
    { 
     get { return _SelectedResource; } 
     set 
     { 
      if (_SelectedResource != value) 
      { 
       _SelectedResource = value; 
       RaisePropertyChanged("SelectedResource"); 
      } 
     } 
    } 

    public RelayCommand CmdSave { get; private set; } 
    public RelayCommand CmdUndo { get; private set; } 
    public RelayCommand CmdAdd { get; private set; } 
    public RelayCommand CmdDelete { get; private set; } 
    void setupCommands() 
    { 
     CmdSave = new RelayCommand(() => 
      { 
       workProvider.SaveChanges(() => 
        { 
         DispatcherHelper.CheckBeginInvokeOnUI(() => 
          { 
           System.Windows.MessageBox.Show("Saved"); 
          }); 
        }); 
      }); 
     CmdUndo = new RelayCommand(() => 
      { 
       workProvider.UndoChanges(); 
       Resources.View.Refresh(); 
      }); 
     CmdAdd = new RelayCommand(() => 
      { 
       Resource newResource = new Resource() 
       { 
        ResourceID = Guid.NewGuid(), 
        Rate = 125, 
        Title = "Staff", 
        UserName = "jsmith" 
       }; 
       workProvider.AddResource(newResource); 
      }); 
     CmdDelete = new RelayCommand(() => 
     { 
      workProvider.DelResource(_SelectedResource); 
     }); 
    } 
} 

번째 방법은 확실히 바이 2 회 (서버에서 1 시간 및 상기 제 시간을 CollectionViewSource의 구성에있어서의 필터의 이벤트 핸들러를 추가 요구하고, 필터링 데이터로 간주 될 수 있지만 CollectionViewSource)를 사용하면 다음과 같은 이점이 있습니다. 단일 컬렉션이있어 컬렉션 알림을 더 간단하고 쉽게 관리 할 수 ​​있습니다. 컬렉션은 서버에 제출 될 실제 컬렉션입니다. 추가/삭제를 간단하게 관리 할 수 ​​있습니다. 올바른 컬렉션에서 엔티티를 추가/제거하지 않아서 제출할 때 추가/삭제 기능을 시작할 수 없기 때문입니다.

마지막으로 확인해야 할 사항은 다음과 같습니다. collectionviewsource에서 뷰에 영향을주는 여러 변경을 수행 할 때 DeferRefresh()를 사용해야한다는 것을 알고 있습니다.이렇게하면 내부 변경으로 인해 정렬, 그룹화 등의 새로 고침이 발생할 수있는 불필요한 새로 고침을 방지 할 수 있습니다. UI에서 일부 업데이트 변경 사항을 처리 할 때 .View.Refresh()를 호출하는 것도 중요합니다. .View.Refresh()는 예기치 않은 UI 업데이트를 방지하는 대신 UI 업데이트를 실제로 발생시키기 때문에 DeferRefresh()보다주의하는 것이 더 중요합니다.

다른 사람들에게 도움이 될지 모르겠지만 그렇게되기를 바랍니다. 나는 이것들을 통해 일하고 이것을 이해하려고 노력하는 데 시간을 보낸다. 추가 할 사항이나 기타 사항이 있으시면 언제든지 알려 주시기 바랍니다.

0

Ryan, this post on collection binding (및 관련 항목 중 일부)을 살펴 보는 것이 좋습니다. 구현은 확실히 합리적인 일이지만, 프레임 워크 수준에서 이미 해결 된 몇 가지 문제와 씨름하고 있음을 알 수 있습니다.