Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

MVVM and the WPF DataGrid

, 23 Sep 2009
Using MVVM, particularly with the WPF DataGrid
datagridopsdemo.zip
DataGridOpsDemo
DataGridOpsDemo
bin
Debug
DataGridOpsDemo.exe
DataGridOpsDemo.vshost.exe
DataGridOpsDemo.vshost.exe.manifest
WPFToolkit.dll
Domain
Images
delete_item.png
Properties
Settings.settings
UtilityClasses
View
delete_item.png
new_item.png
ViewModel
Commands
Services
ValueConverters
Library
WPFToolkit.dll
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using Microsoft.Windows.Controls;

namespace DataGridOpsDemo
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Fields

        // Member variables
        private int m_OriginalIndex;
        private DataGridRow m_OldRow;
        private GroceryItem m_TargetItem;
        private MainWindowViewModel m_ViewModel;

        #endregion

        #region Constructor

        public MainWindow()
        {
            InitializeComponent();
        }

        #endregion

        #region Static Methods

        private static T FindVisualParent<T>(UIElement element) where T : UIElement
        {
            var parent = element;
            while (parent != null)
            {
                var correctlyTyped = parent as T;
                if (correctlyTyped != null)
                {
                    return correctlyTyped;
                }

                parent = VisualTreeHelper.GetParent(parent) as UIElement;
            }
            return null;
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Updates the grid as a drag progresses
        /// </summary>
        private void OnMainGridCheckDropTarget(object sender, DragEventArgs e)
        {
            var row = FindVisualParent<DataGridRow>(e.OriginalSource as UIElement);

            /* If we are over a row that contains a GroceryItem, set 
             * the drop-line above that row. Otherwise, do nothing. */

            // Set the DragDropEffects 
            if ((row == null) || !(row.Item is GroceryItem))
            {
                e.Effects = DragDropEffects.None;
            }
            else
            {
                var currentIndex = row.GetIndex();
                
                // Erase old drop-line
                if (m_OldRow != null) m_OldRow.BorderThickness = new Thickness(0);

                // Draw new drop-line
                var direction = (currentIndex - m_OriginalIndex);
                if (direction < 0) row.BorderThickness = new Thickness(0, 2, 0, 0);
                else if (direction > 0) row.BorderThickness = new Thickness(0, 0, 0, 2);

                // Reset old row
                m_OldRow = row;
            }
        }

        /// <summary>
        /// Gets the view model from the data Context and assigns it to a member variable.
        /// </summary>
        private void OnMainGridDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            m_ViewModel = (MainWindowViewModel)this.DataContext;
        }

        /// <summary>
        /// Process a row drop on the DataGrid.
        /// </summary>
        private void OnMainGridDrop(object sender, DragEventArgs e)
        {
            e.Effects = DragDropEffects.None;
            e.Handled = true;

            // Verify that this is a valid drop and then store the drop target
            var row = FindVisualParent<DataGridRow>(e.OriginalSource as UIElement);
            if (row != null)
            {
                m_TargetItem = row.Item as GroceryItem;
                if (m_TargetItem != null)
                {
                    e.Effects = DragDropEffects.Move;
                }
            }

            // Erase last drop-line
            if (m_OldRow != null) m_OldRow.BorderThickness = new Thickness(0, 0, 0, 0);
        }

        /// <summary>
        /// Processes a drag in the main grid.
        /// </summary>
        private void OnMainGridMouseMove(object sender, MouseEventArgs e)
        {
            // Exit if shift key and left mouse button aren't pressed
            if (e.LeftButton != MouseButtonState.Pressed) return;
            if (Keyboard.Modifiers != ModifierKeys.Shift) return;

            /* We use the m_MouseDirection value in the 
             * OnMainGridCheckDropTarget() event handler. */

            // Find the row the mouse button was pressed on
            var row = FindVisualParent<DataGridRow>(e.OriginalSource as FrameworkElement);
            m_OriginalIndex = row.GetIndex();

            // If the row was already selected, begin drag
            if ((row != null) && row.IsSelected)
            {
                // Get the grocery item represented by the selected row
                var selectedItem = (GroceryItem) row.Item;
                var finalDropEffect = DragDrop.DoDragDrop(row, selectedItem, DragDropEffects.Move);
                if ((finalDropEffect == DragDropEffects.Move) && (m_TargetItem != null))
                {
                    /* A drop was accepted. Determine the index of the item being 
                     * dragged and the drop location. If they are different, then 
                     * move the selectedItem to the new location. */

                    // Move the dragged item to its drop position
                    var oldIndex = m_ViewModel.GroceryList.IndexOf(selectedItem);
                    var newIndex = m_ViewModel.GroceryList.IndexOf(m_TargetItem);
                    if (oldIndex != newIndex) m_ViewModel.GroceryList.Move(oldIndex, newIndex);
                    m_TargetItem = null;
                }
            }
        }

#endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

David Veeneman
Software Developer (Senior) Foresight Systems
United States United States
David Veeneman is a financial planner and software developer. He is the author of "The Fortune in Your Future" (McGraw-Hill 1998). His company, Foresight Systems, develops planning and financial software.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 23 Sep 2009
Article Copyright 2009 by David Veeneman
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid