2009-12-17 2 views
1

MVVM 디자인 패턴과 함께 Silverlight 3.0 DataGrid를 사용하려고합니다. 내 페이지에는 DataGrid와 (Composite Application Library의) 명령을 사용하여 VM의 컬렉션에 항목을 추가하는 버튼이 있습니다. 이 잘 작동하고 새 항목이 표시되고 선택됩니다.MVVM을 사용하여 Silverlight 3 DataGrid에서 새로 추가 된 행 편집

해결할 수없는 문제는 행 편집을 시작하는 방법입니다. 사용자가 추가 버튼, 즉 포커스를 DataGrid로 설정하고 새 행을 편집 모드로 클릭하면 새 행을 바로 편집 할 수 있습니다.

뷰에서 XAML입니다 :

<Grid x:Name="LayoutRoot"> 
    <StackPanel> 
     <data:DataGrid ItemsSource="{Binding DataView}"/> 
     <Button cmd:Click.Command="{Binding AddItemCommand}" Content="Add" /> 
    </StackPanel> 
</Grid> 

코드는 뒤에 VM의 인스턴스를 생성하고 뷰의 DataContext를을 설정하는 코드 한 줄이있다.

는 VM 코드는 다음과 같습니다

public class VM 
{ 
    public List<TestData> UnderlyingData { get; set; } 
    public PagedCollectionView DataView { get; set; } 
    public ICommand AddItemCommand { get; set; } 

    public VM() 
    { 
     AddItemCommand = new DelegateCommand<object>(o => 
      { 
       DataView.AddNew(); 
      }); 

     UnderlyingData = new List<TestData>(); 
     UnderlyingData.Add(new TestData() { Value = "Test" }); 

     DataView = new PagedCollectionView(UnderlyingData); 
    } 
} 

public class TestData 
{ 
    public string Value { get; set; } 

    public TestData() 
    { 
     Value = "<new>"; 
    } 

    public override string ToString() 
    { 
     return Value.ToString(); 
    } 
} 

가 무엇 MVVM 디자인 패턴을 사용하여이 문제를 해결하는 가장 좋은 방법이 있을까요?

답변

0

ui 구성 요소에 직접 액세스하는 것에 대해 이야기 할 때마다 mvvm의 요점이 누락됩니다. UI가 뷰 모델에 바인딩되므로 대신 뷰 모델을 변경하는 방법을 찾아야합니다.

+1

정확합니다. MVVM을 사용하지 않으면이 문제를 쉽게 해결할 수 있습니다. 내 질문은 MVVM 패턴을 고수하면서 원하는 결과를 얻는 방법입니다. – bart

1

나는 똑같은 문제에 직면했다. 인터페이스 ISupportEditingState를 도입했습니다.

public interface ISupportEditingState 
{ 
    EditingState EditingState { get; set; } 
} 

내 VM이 구현합니다. 그리고 나서 DataGrid와 내 VM의 편집 상태를 동기화하기 위해이 동작을 작성했습니다.

public class SynchroniseDataGridEditingStateBehaviour : Behavior<DataGrid> 
{ 
    public static readonly DependencyProperty EditingStateBindingProperty = 
     DependencyProperty.Register("EditingStateBinding", typeof(ISupportEditingState), 
     typeof(SynchroniseDataGridEditingStateBehaviour), new PropertyMetadata(OnEditingStateBindingPropertyChange)); 

    private bool _attached; 
    private bool _changingEditingState; 

    public ISupportEditingState EditingStateBinding 
    { 
     get { return (ISupportEditingState)GetValue(EditingStateBindingProperty); } 
     set { SetValue(EditingStateBindingProperty, value); } 
    } 

    private static void OnEditingStateBindingPropertyChange(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var b = d as SynchroniseDataGridEditingStateBehaviour; 
     if (b == null) 
      return; 

     var oldNotifyChanged = e.OldValue as INotifyPropertyChanged; 
     if (oldNotifyChanged != null) 
      oldNotifyChanged.PropertyChanged -= b.OnEditingStatePropertyChanged; 

     var newNotifyChanged = e.NewValue as INotifyPropertyChanged; 
     if (newNotifyChanged != null) 
      newNotifyChanged.PropertyChanged += b.OnEditingStatePropertyChanged; 

     var newEditingStateSource = e.NewValue as ISupportEditingState; 
     if (newEditingStateSource.EditingState == EditingState.Editing) 
     { 
      // todo: mh: decide on this behaviour once again. 
      // maybe it's better to start editing if selected item is already bound in the DataGrid 
      newEditingStateSource.EditingState = EditingState.LastCancelled; 
     } 
    } 

    private static readonly string EditingStatePropertyName = 
     CodeUtils.GetPropertyNameByLambda<ISupportEditingState>(ses => ses.EditingState); 

    private void OnEditingStatePropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     if (_changingEditingState || !_attached || e.PropertyName != EditingStatePropertyName) 
      return; 

     _changingEditingState = true; 

     var editingStateSource = sender as ISupportEditingState; 
     if (editingStateSource == null) 
      return; 

     var grid = AssociatedObject; 
     var editingState = editingStateSource.EditingState; 
     switch (editingState) 
     { 
      case EditingState.Editing: 
       grid.BeginEdit(); 
       break; 
      case EditingState.LastCancelled: 
       grid.CancelEdit(); 
       break; 
      case EditingState.LastCommitted: 
       grid.CommitEdit(); 
       break; 
      default: 
       throw new InvalidOperationException("Provided EditingState is not supported by the behaviour."); 
     } 

     _changingEditingState = false; 
    } 

    protected override void OnAttached() 
    { 
     var grid = AssociatedObject; 
     grid.BeginningEdit += OnBeginningEdit; 
     grid.RowEditEnded += OnEditEnded; 
     _attached = true; 
    } 

    protected override void OnDetaching() 
    { 
     var grid = AssociatedObject; 
     grid.BeginningEdit -= OnBeginningEdit; 
     grid.RowEditEnded -= OnEditEnded; 
     _attached = false; 
    } 

    void OnEditEnded(object sender, DataGridRowEditEndedEventArgs e) 
    { 
     if (_changingEditingState) 
      return; 

     EditingState editingState; 
     if (e.EditAction == DataGridEditAction.Commit) 
      editingState = EditingState.LastCommitted; 
     else if (e.EditAction == DataGridEditAction.Cancel) 
      editingState = EditingState.LastCancelled; 
     else 
      return; // if DataGridEditAction will ever be extended, this part must be changed 
     EditingStateBinding.EditingState = editingState; 
    } 

    void OnBeginningEdit(object sender, DataGridBeginningEditEventArgs e) 
    { 
     if (_changingEditingState) 
      return; 
     EditingStateBinding.EditingState = EditingState.Editing; 
    } 
} 

제게 도움이 되길 바랍니다.

+0

코드를 게시 해 주셔서 감사합니다. 그 프로젝트에서 더 이상 일하지 않기 때문에 쉽게 테스트 할 수 없지만, 다른 사람들이 유용하다고 생각하면 아마도 여기에 의견을 말할 수 있습니다. – bart

관련 문제