Click here to Skip to main content
15,886,258 members
Articles / Programming Languages / C#

Build Your Own DataGrid for Silverlight: Step 2

Rate me:
Please Sign up or sign in to vote.
4.39/5 (9 votes)
3 Jun 2009CPOL59 min read 46.5K   854   26  
Implementation of editing and validation features.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.Windows;
using System.Windows.Input;
using System.Collections.Generic;
using System.Windows.Media;
using System.Windows.Controls;
using System;

namespace Open.Windows.Controls
{
    public partial class ContainerItem : HandyListItem
    {
        private class CellPosition
        {
            public CellPosition(Cell cell, Point position)
            {
                Cell = cell;
                Position = position;
            }

            public Cell Cell
            {
                get;
                private set;
            }

            public Point Position
            {
                get;
                private set;
            }
        }

        private class CellPositionComparer : IComparer<CellPosition>
        {

            public int Compare(CellPosition x, CellPosition y)
            {
                if (x.Position.Y > y.Position.Y)
                    return 1;
                else if (x.Position.Y < y.Position.Y)
                    return -1;

                if (x.Position.X > y.Position.X)
                    return 1;
                else if (x.Position.X < y.Position.X)
                    return -1;

                return 0;
            }

        }

        public string GetFirstCellName()
        {
            this.UpdateLayout();

            List<CellPosition> cellPositions = new List<CellPosition>();
            List<Cell> cells = GetCells();
            UIElement rootVisual = Application.Current.RootVisual;
            foreach (Cell cell in cells)
            {
                cellPositions.Add(new CellPosition(cell, Cell.GetPosition(cell, rootVisual)));
            }

            cellPositions.Sort(new CellPositionComparer());

            foreach (CellPosition cellPosition in cellPositions)
            {
                if (cellPosition.Cell.IsTabStop)
                    return cellPosition.Cell.Name;
            }

            return null;

        }

        public string GetLastCellName()
        {
            this.UpdateLayout();

            List<CellPosition> cellPositions = new List<CellPosition>();
            List<Cell> cells = GetCells();
            UIElement rootVisual = Application.Current.RootVisual;
            foreach (Cell cell in cells)
            {
                cellPositions.Add(new CellPosition(cell, Cell.GetPosition(cell, rootVisual)));
            }

            cellPositions.Sort(new CellPositionComparer());

            for (int cellIndex = cellPositions.Count - 1; cellIndex >= 0; cellIndex--)
            {
                CellPosition cellPosition = cellPositions[cellIndex];
                if (cellPosition.Cell.IsTabStop)
                    return cellPosition.Cell.Name;
            }

            return null;

        }

        List<Cell> cellCollection;
        private List<Cell> GetCells()
        {
            if (cellCollection == null)
            {
                cellCollection = new List<Cell>();
                DependencyObject firstChild = GetFirstTreeChild();
                if (firstChild != null)
                    AddChildrenCells(firstChild, cellCollection);
            }

            return cellCollection;
        }

        private void AddChildrenCells(DependencyObject parent, List<Cell> cellsCollection)
        {
            int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
            for (int index = 0; index < childrenCount; index++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(parent, index);
                Cell childCell = child as Cell;
                if (childCell != null)
                    cellsCollection.Add(childCell);
                else
                    AddChildrenCells(child, cellsCollection);
            }

        }

        public override void OnApplyTemplate()
        {
            cellCollection = null;

            _OnApplyTemplate();
            base.OnApplyTemplate();
        }


        public bool FocusCell(string cellName)
        {
            HandyContainer parentContainer = HandyContainer.GetParentContainer(this);
            if ((parentContainer != null) && parentContainer.IsCurrentItemEditedOrDirty)
            {
                bool canNavigate = true;
                bool isEditedSameItem = parentContainer.CurrentEditedOrDirtyItem == this;
                if (isEditedSameItem)
                {
                    if (parentContainer.IsCurrentCellInEditMode && (parentContainer.CurrentEditedCell.Name != cellName))
                        canNavigate = parentContainer.CommitEdit(false);
                }
                else
                    canNavigate = parentContainer.Validate(false);

                if (!canNavigate)
                    return false;
            }

            object focusedElement = FocusManager.GetFocusedElement();
            FrameworkElement firstChild = GetFirstTreeChild() as FrameworkElement;
            if (firstChild != null)
            {
                Cell cell = firstChild.FindName(cellName) as Cell;
                if (cell != null)
                {
                    if (cell.Focus())
                    {
                        if (!TreeHelper.IsChildOf(this, focusedElement as DependencyObject))
                        {
                            if (parentContainer != null)
                                parentContainer._OnNavigatorSetKeyboardFocus(this);
                        }
                        return true;
                    }
                }
            }

            return false;
        }        

        private DependencyObject GetFirstTreeChild()
        {
            ContentPresenter presenter = this.ContentPresenter;
            if (presenter != null)
            {
                if (VisualTreeHelper.GetChildrenCount(presenter) > 0)
                    return VisualTreeHelper.GetChild(presenter, 0);
            }

            return null;

        }

        public Cell FindCell(string cellName)
        {
            FrameworkElement firstChild = GetFirstTreeChild() as FrameworkElement;
            if (firstChild != null)
                return firstChild.FindName(cellName) as Cell;

            return null;
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);

            if (!e.Handled)
            {
                if ((e.Key == Key.Home) && ((Keyboard.Modifiers & ModifierKeys.Control) != ModifierKeys.Control))
                {
                    string firstCellName = GetFirstCellName();
                    if (!string.IsNullOrEmpty(firstCellName))
                    {
                        if (FocusCell(firstCellName))
                            e.Handled = true;

                    }
                }

                if ((e.Key == Key.End) && ((Keyboard.Modifiers & ModifierKeys.Control) != ModifierKeys.Control))
                {
                    string lastCellName = GetLastCellName();
                    if (!string.IsNullOrEmpty(lastCellName))
                    {
                        if (FocusCell(lastCellName))
                            e.Handled = true;

                    }
                }
            }
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            bool canNavigate = true;
            HandyContainer parentContainer = HandyContainer.GetParentContainer(this);
            if ((parentContainer != null) && (parentContainer.IsCurrentItemEditedOrDirty))
            {
                bool isEditedSameItem = parentContainer.CurrentEditedOrDirtyItem == this;
                if (isEditedSameItem)
                {
                    if (!TreeHelper.IsChildOf(parentContainer.CurrentEditedCell, e.OriginalSource as DependencyObject))
                        canNavigate = parentContainer.CommitEdit(false);
                }
                else
                    canNavigate = parentContainer.Validate(false);
            }

            if (canNavigate)
                base.OnMouseLeftButtonDown(e);
            else
            {
                e.Handled = true;
                FrameworkElement focusElement = FocusManager.GetFocusedElement() as FrameworkElement;
                if (!TreeHelper.IsChildOf(parentContainer, focusElement))
                    parentContainer.ResumeEdit();
            }

        }

        protected override void OnIsExpandedChanging(Netika.Windows.Controls.IsExpandedChangingEventArgs e)
        {
            HandyContainer parentContainer = HandyContainer.GetParentContainer(this);
            if ((parentContainer != null) && (!parentContainer.Validate()))
                e.Cancel = true;
            else
                base.OnIsExpandedChanging(e);
        }    

        private int isDirtyCount;
        internal int IsDirtyCount
        {
            get { return isDirtyCount; }
            set
            {
                if (isDirtyCount != value)
                {
                    isDirtyCount = value;

                    HandyContainer parentContainer = HandyContainer.GetParentContainer(this);
                    if (parentContainer != null)
                    {
                        if (isDirtyCount > 0)
                            parentContainer.CurrentDirtyItem = this;
                        else
                            parentContainer.CurrentDirtyItem = null;
                    }
                }
            }
        }

        public bool IsDirty
        {
            get { return IsDirtyCount > 0; }
        }

        public static ContainerItem GetParentContainerItem(FrameworkElement element)
        {
            DependencyObject parentElement = element;
            while (parentElement != null)
            {
                ContainerItem parentContainerItem = parentElement as ContainerItem;
                if (parentContainerItem != null)
                    return parentContainerItem;

                parentElement = VisualTreeHelper.GetParent(parentElement);
            }

            return null;
        }

        internal bool Validate(bool keepFocus)
        {
            HandyContainer parentContainer = HandyContainer.GetParentContainer(this);
            if (parentContainer != null)
            {
                if (parentContainer.IsCurrentCellInEditMode && !parentContainer.CommitEdit(keepFocus))
                    return false;

                if (!IsDirty)
                    return true;

                ItemValidatingEventArgs eventArgs = new ItemValidatingEventArgs(this, false);
                parentContainer._OnCurrentItemValidating(eventArgs);
                if (eventArgs.Cancel)
                {
                    IsValid = false;
                    return false;
                }

                IsValid = true;

                IsDirtyCount = 0;

                parentContainer._OnCurrentItemValidated(EventArgs.Empty);
            }

            return true;
        }

        private bool isValid = true;
        public bool IsValid
        {
            get { return isValid; }
            internal set
            {
                if (isValid != value)
                {
                    isValid = value;
                    if (isValid)
                        VisualStateManager.GoToState(this, "Valid", true);
                    else
                        VisualStateManager.GoToState(this, "NotValid", true);
                }
            }
        }

        protected override void OnGotFocus(RoutedEventArgs e)
        {
            HandyContainer parentContainer = HandyContainer.GetParentContainer(this);
            if (parentContainer != null)
            {
                if ((parentContainer.CurrentDirtyItem != null) && (parentContainer.CurrentDirtyItem != this))
                    throw new InvalidOperationException("Invalid navigation operation");
            }

            base.OnGotFocus(e);
        }

        private bool isFocusProtected;
        private bool isTabStop;
        internal void FocusProtect(Cell skipedCell)
        {
            if (isFocusProtected)
                return;

            isTabStop = this.IsTabStop;
            this.IsTabStop = false;
            List<Cell> cells = this.GetCells();
            foreach (Cell cell in cells)
                if (cell != skipedCell)
                    cell.FocusProtect();

            isFocusProtected = true;
        }

        internal void FocusUnProtect(Cell skipedCell)
        {
            if (!isFocusProtected)
                return;

            IsTabStop = isTabStop;
            List<Cell> cells = this.GetCells();
            foreach (Cell cell in cells)
                if (cell != skipedCell)
                    cell.FocusUnProtect();

            isFocusProtected = false;
        }        
    }
}

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)


Written By
Web Developer
Belgium Belgium
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions