2009-12-17 42 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

每當你談論直接訪問用戶界面組件,你有點錯過了mvvm的要點。 ui綁定到視圖模型,所以找到一種方法來改變viewmodel。

+1

沒錯。如果我不使用MVVM,我可以很容易地解決這個問題。我的問題是如何實現我想要的結果,同時仍然堅持使用MVVM模式。 – bart

1

我面臨同樣的問題。我介紹了接口ISupportEditingState:

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

我的VM實現它。然後,我寫了這個行爲同步DataGrid和我的虛擬機的編輯狀態:

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