2

I want my DataGrid scroll to bottom as new item added to underlying ObservableCollection. To achieve this, I make an interface similar to ICommand but in "reverse" way.

public interface IViewModelCommand
{
    void Execute(object parameter);
}

Implementation

public class ViewModelRelayCommand : IViewModelCommand
{
    private readonly Action<object> _action;
    public ViewModelRelayCommand(Action<object> action)
    {
        if(action == null)
            throw new ArgumentNullException("action");

        _action = action;
    }

    public void Execute(object parameter)
    {
        _action(parameter);
    }
}

My ViewModel

    private IViewModelCommand _scrollAction;
    public IViewModelCommand ScrollAction
    {
        get { return _scrollAction; }
        set
        {
            if (_scrollAction == value)
                return;
            _scrollAction = value;OnPropertyChanged();
        }
    }

Then I create behavior for my DataGrid. (Scroll to end code taken from here)

public sealed class DataGridBehavior : Behavior<DataGrid>
{
        public static readonly DependencyProperty ScrollToEndProperty =
            DependencyProperty.Register (
                "ScrollToEnd",
                typeof(IViewModelCommand),
                typeof(DataGridBehavior),
                new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None)
            );

        public IViewModelCommand ScrollToEnd
        {
            get { return (IViewModelCommand)GetValue(ScrollToEndProperty); }
            set { SetValue(ScrollToEndProperty, value); }
        }

        protected override void OnAttached()
        {
            base.OnAttached();
            ScrollToEnd = new ViewModelRelayCommand(Scroll);
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            ScrollToEnd = null;
        }

        private void Scroll(object parameter)
        {
            var mainDataGrid = AssociatedObject;
            if (mainDataGrid.Items.Count > 0)
            {
                var border = VisualTreeHelper.GetChild(mainDataGrid, 0) as Decorator;
                if (border != null)
                {
                    var scroll = border.Child as ScrollViewer;
                    if (scroll != null) scroll.ScrollToEnd();
                }
            }
        }
    }

And attach it to my DataGrid

        <i:Interaction.Behaviors>
            <local:DataGridBehavior ScrollToEnd="{Binding ScrollAction, Mode=OneWayToSource}" />
        </i:Interaction.Behaviors>

Then from my ViewModel I just call if (_scrollAction != null) _scrollAction.Execute(null); to scroll my grid and it works very well.

My question, is this violating MVVM?

Community
  • 1
  • 1
Niyoko
  • 7,512
  • 4
  • 32
  • 59

1 Answers1

2

just a little bit...

In my experience MVVM is most healthfully practiced as a rough guideline. There's no use in finding solutions to keep MVVM straight when your actual programming task doesn't require it, especially if you got working solutions up and running.

But have you thought of an event instead of the command approach?

In that case this may be useful to you: How can I Have a WPF EventTrigger on a View trigger when the underlying Viewmodel dictates it should?

Community
  • 1
  • 1
  • Just to clarify, it's my hobby project to learn about MVVM. I am not required to deliver it as fast as possible and like to find an ideal way. – Niyoko Mar 17 '15 at 06:15