【问题标题】:Editing newly added row in Silverlight 3 DataGrid using MVVM使用 MVVM 在 Silverlight 3 DataGrid 中编辑新添加的行
【发布时间】:2010-12-27 12:01:33
【问题描述】:

我正在尝试将 Silverlight 3.0 DataGrid 与 MVVM 设计模式一起使用。我的页面有一个 DataGrid 和一个按钮,该按钮使用命令(来自复合应用程序库)将项目添加到 VM 中的集合。这工作正常,新项目被显示和选择。

我无法解决的问题是如何开始编辑行。我希望新行在用户单击“添加”按钮时立即可编辑,即焦点设置为 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 设计模式解决此问题的最佳方法是什么?

【问题讨论】:

    标签: c# silverlight silverlight-3.0 datagrid mvvm


    【解决方案1】:

    我遇到了同样的问题。我已经引入了接口 ISupportEditingState:

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

    我的虚拟机实现了它。然后我写了这个行为来同步 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;
        }
    }
    

    对我来说没问题,希望对你有帮助。

    【讨论】:

    • 感谢您发布代码。我不能轻易测试它,因为我不再从事那个项目,但如果其他人觉得它有用,也许他们可以在这里发表评论。
    【解决方案2】:

    当你谈到直接访问 ui 组件时,你有点忽略了 mvvm 的意义。 ui 绑定到 viewmodel,因此请找到一种方法来更改 viewmodel。

    【讨论】:

    • 没错。如果我不使用 MVVM,我可以轻松解决这个问题。我的问题是如何在仍然坚持 MVVM 模式的同时达到我想要的结果。
    猜你喜欢
    • 2023-04-01
    • 1970-01-01
    • 2011-03-10
    • 1970-01-01
    • 1970-01-01
    • 2010-12-20
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    相关资源
    最近更新 更多