Редактирование новой добавленной строки в Silverlight 3 DataGrid с использованием MVVM - PullRequest
1 голос
/ 17 декабря 2009

Я пытаюсь использовать DataGrid Silverlight 3.0 с шаблоном проектирования MVVM. На моей странице есть DataGrid и кнопка, которая добавляет элемент в коллекцию на виртуальной машине с помощью команды (из библиотеки составных приложений). Это прекрасно работает, и новый элемент отображается и выбирается.

Проблема, которую я не могу решить, - это как начать редактирование строки. Я хочу, чтобы новая строка была немедленно редактируемой, когда пользователь нажимает кнопку «Добавить», т.е. фокус устанавливается на DataGrid, а новая строка в режиме редактирования.

Это XAML в представлении:

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

Код позади имеет одну строку кода, которая создает экземпляр виртуальной машины и устанавливает DataContext представления.

Код виртуальной машины:

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?

Ответы [ 2 ]

1 голос
/ 20 августа 2010

Я столкнулся с той же проблемой. Я представил интерфейс ISupportEditingState:

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

Моя виртуальная машина реализует это. И затем я написал это поведение для синхронизации состояния редактирования 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 голосов
/ 17 декабря 2009

Всякий раз, когда вы говорите о прямом доступе к компонентам пользовательского интерфейса, вам не хватает точки mvvm. Пользовательский интерфейс связывается с моделью представления, поэтому найдите способ изменить модель представления.

...