Click here to Skip to main content
15,886,004 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;
using System.Windows;
using Netika.Windows.Controls;
using System.Windows.Media;
using System.Windows.Input;
using System.Windows.Controls;

namespace Open.Windows.Controls
{
    public partial class HandyContainer : HandyListControl
    {
        public event EventHandler CurrentCellNameChanged;
        private string currentCellName;
        public string CurrentCellName
        {
            get { return currentCellName; }
            internal set
            {
                if (currentCellName != value)
                {
                    currentCellName = value;
                    OnCurrentCellNameChanged(EventArgs.Empty);

                }
            }
        }

        protected virtual void OnCurrentCellNameChanged(EventArgs e)
        {
            if (CurrentCellNameChanged != null)
                CurrentCellNameChanged(this, e);
        }

        
        internal void _OnNavigatorSetKeyboardFocus(UIElement item)
        {
            this.OnNavigatorSetKeyboardFocus(item);
        }

        protected override void OnNavigatorSetKeyboardFocus(UIElement item)
        {
            base.OnNavigatorSetKeyboardFocus(item);
            
            GridSpatialNavigator gridSpatialNavigator = GetGridSpatialNavigator();
            if (gridSpatialNavigator != null)
            {
                if ((gridSpatialNavigator.LastKeyProcessed == Key.Down) ||
                     (gridSpatialNavigator.LastKeyProcessed == Key.Up) ||
                     (gridSpatialNavigator.LastKeyProcessed == Key.PageDown) ||
                     (gridSpatialNavigator.LastKeyProcessed == Key.PageUp))
                {
                    if (item != null)
                    {
                        if (!String.IsNullOrEmpty(CurrentCellName))
                        {
                            ContainerItem newItem = (ContainerItem)item;
                            newItem.FocusCell(CurrentCellName);
                        }
                    }
                }
            }
        }

        public ContainerItem CurrentItem
        {
            get { return this.GetElement(this.HoldFocusItem) as ContainerItem; }
        }

        public int CurrentItemIndex
        {
            get
            {
                ContainerItem currentItem = this.CurrentItem;
                if (currentItem != null)
                {
                    if (this.VirtualMode == VirtualMode.On)
                    {
                        int currentItemIndex = this.ItemsHost.Children.IndexOf(currentItem);
                        return this.VirtualPageStartIndex + currentItemIndex;
                    }
                    else
                        return this.ItemsHost.Children.IndexOf(currentItem);

                }
                return -1;
            }
        }

        private GridSpatialNavigator GetGridSpatialNavigator()
        {
            GPanel gPanel = this.ItemsHost as GPanel;
            if (gPanel != null)
                return gPanel.KeyNavigator as GridSpatialNavigator;

            return null;
        }

        public void EnsureCellIsVisible(Cell cell)
        {
            GStackPanel itemsHost = (GStackPanel)this.ItemsHost;
            Point cellPosition = Cell.GetPosition(cell, itemsHost);
            if (cellPosition.X < 0)
                this.HorizontalOffset += cellPosition.X;
            else if ((cellPosition.X + cell.ActualWidth > itemsHost.ViewportWidth) && (cell.ActualWidth <= this.ViewportWidth))
                this.HorizontalOffset += cellPosition.X + cell.ActualWidth - this.ViewportWidth;
        }

        public static HandyContainer GetParentContainer(FrameworkElement element)
        {
            DependencyObject parentElement = element;
            while (parentElement != null)
            {
                HandyContainer parentContainer = parentElement as HandyContainer;
                if (parentContainer != null)
                    return parentContainer;

                parentElement = VisualTreeHelper.GetParent(parentElement);
            }

            return null;
        }

        public bool IsCurrentCellDirty
        {
            get { return CurrentDirtyCell != null; }

        }

        private Cell currentDirtyCell;
        internal Cell CurrentDirtyCell
        {
            get { return currentDirtyCell; }
            set
            {
                if (currentDirtyCell != value)
                {
                    currentDirtyCell = value;
                    OnIsCurrentCellDirtyChanged(EventArgs.Empty);
                }

            }
        }

        public event EventHandler IsCurrentCellDirtyChanged;
        protected virtual void OnIsCurrentCellDirtyChanged(EventArgs e)
        {
            if (IsCurrentCellDirtyChanged != null)
                IsCurrentCellDirtyChanged(this, e);
        }

        public bool BeginEdit()
        {
            Cell currentCell = GetCurrentCell();
            if (currentCell != null)
                return currentCell.BeginEdit();

            return false;
        }

        public bool CommitEdit()
        {
            return CommitEdit(true);
        }

        public bool CommitEdit(bool keepFocus)
        {
            if (CurrentEditedCell != null)
                return CurrentEditedCell.CommitEdit(keepFocus);

            return true;
        }

        public bool CancelEdit()
        {
            return CancelEdit(true);
        }

        public bool CancelEdit(bool keepFocus)
        {
            if (CurrentEditedCell != null)
                return CurrentEditedCell.CancelEdit(keepFocus);

            return true;
        }

        private Cell GetCurrentCell()
        {
            ContainerItem currentItem = this.CurrentItem;
            if ((currentItem != null) && !String.IsNullOrEmpty(this.CurrentCellName))
                return currentItem.FindCell(this.CurrentCellName);

            return null;
        }

        internal void _OnCurrentCellBeginEditing(GCancelEventArgs e)
        {
            OnCurrentCellBeginEditing(e);
        }

        public event EventHandler<GCancelEventArgs> CurrentCellBeginEditing;
        protected virtual void OnCurrentCellBeginEditing(GCancelEventArgs e)
        {
            if (CurrentCellBeginEditing != null)
                CurrentCellBeginEditing(this, e);
        }

        internal void _OnCurrentCellBeginEdited(EventArgs e)
        {
            CurrentEditedCell = this.GetCurrentCell();
            CurrentEditedItem = ContainerItem.GetParentContainerItem(CurrentEditedCell);
            CurrentEditedItem.FocusProtect(CurrentEditedCell);
            if (CurrentDirtyItem == null)
                ItemsFocusProtect();
            OnCurrentCellBeginEdited(e);

        }    

        public event EventHandler CurrentCellBeginEdited;
        protected virtual void OnCurrentCellBeginEdited(EventArgs e)
        {
            if (CurrentCellBeginEdited != null)
                CurrentCellBeginEdited(this, e);
        }

        public event EventHandler CurrentCellEndEdit;
        internal void _OnCurrentCellEndEdit(EventArgs e)
        {
            CurrentEditedItem.FocusUnProtect(CurrentEditedCell);
            if (currentDirtyItem == null)
                ItemsFocusUnProtect();
            CurrentEditedCell = null;
            CurrentEditedItem = null;
            OnCurrentCellEndEdit(e);
        }

        internal void OnCurrentCellEndEdit(EventArgs e)
        {
            if (CurrentCellEndEdit != null)
                CurrentCellEndEdit(this, e);
        }

        public bool IsCurrentCellInEditMode
        {
            get { return CurrentEditedCell != null; }
        }

        internal Cell CurrentEditedCell
        {
            get;
            set;
        }

        internal void _OnCurrentCellValidating(CellValidatingEventArgs e)
        {
            OnCurrentCellValidating(e);
        }

        public event EventHandler<CellValidatingEventArgs> CurrentCellValidating;
        protected virtual void OnCurrentCellValidating(CellValidatingEventArgs e)
        {
            if (CurrentCellValidating != null)
                CurrentCellValidating(this, e);
        }

        protected override void OnVerticalOffsetChanging(CancelOffsetEventArgs e)
        {
            if (this.IsCurrentItemEditedOrDirty && !this.Validate())
                e.Cancel = true;

            base.OnVerticalOffsetChanging(e);
        }

        internal void _OnCurrentCellValidated(EventArgs e)
        {
            OnCurrentCellValidated(e);
        }

        public event EventHandler CurrentCellValidated;
        protected virtual void OnCurrentCellValidated(EventArgs e)
        {
            if (CurrentCellValidated != null)
                CurrentCellValidated(this, e);
        }

        public bool IsCurrentItemDirty
        {
            get { return CurrentDirtyItem != null; }

        }

        private ContainerItem currentDirtyItem;
        internal ContainerItem CurrentDirtyItem
        {
            get { return currentDirtyItem; }
            set
            {
                if (currentDirtyItem != value)
                {
                    if (value == null)
                        ItemsFocusUnProtect();

                    currentDirtyItem = value;
                    OnIsCurrentItemDirtyChanged(EventArgs.Empty);
                }
            }
        }

        public event EventHandler IsCurrentItemDirtyChanged;
        protected virtual void OnIsCurrentItemDirtyChanged(EventArgs e)
        {
            if (IsCurrentItemDirtyChanged != null)
                IsCurrentItemDirtyChanged(this, e);
        }

        public bool IsCurrentItemEdited
        {
            get { return CurrentEditedItem != null; }

        }

        private ContainerItem currentEditedItem;
        internal ContainerItem CurrentEditedItem
        {
            get { return currentEditedItem; }
            set
            {
                if (currentEditedItem != value)
                {
                    currentEditedItem = value;
                    OnIsCurrentItemEditedChanged(EventArgs.Empty);
                }

            }
        }

        public event EventHandler IsCurrentItemEditedChanged;
        protected virtual void OnIsCurrentItemEditedChanged(EventArgs e)
        {
            if (IsCurrentItemEditedChanged != null)
                IsCurrentItemEditedChanged(this, e);
        }

        internal void _OnCurrentItemValidating(ItemValidatingEventArgs e)
        {
            OnCurrentItemValidating(e);
        }

        public event EventHandler<ItemValidatingEventArgs> CurrentItemValidating;
        protected virtual void OnCurrentItemValidating(ItemValidatingEventArgs e)
        {
            if (CurrentItemValidating != null)
                CurrentItemValidating(this, e);
        }
        internal void _OnCurrentItemValidated(EventArgs e)
        {
            OnCurrentItemValidated(e);
        }

        public event EventHandler CurrentItemValidated;
        protected virtual void OnCurrentItemValidated(EventArgs e)
        {
            if (CurrentItemValidated != null)
                CurrentItemValidated(this, e);
        }

        internal bool IsCurrentItemEditedOrDirty
        {
            get { return IsCurrentItemEdited || IsCurrentItemDirty; }
        }

        internal ContainerItem CurrentEditedOrDirtyItem
        {
            get { return CurrentDirtyItem ?? CurrentEditedItem; }
        }

        public bool Validate()
        {
            return Validate(true);
        }

        public bool Validate(bool keepFocus)
        {
            if (CurrentEditedOrDirtyItem != null)
                return CurrentEditedOrDirtyItem.Validate(keepFocus);

            return true;
        }

        private bool hasFocus = false;
        protected override void OnGotFocus(RoutedEventArgs e)
        {
            base.OnGotFocus(e);
            if (!hasFocus)
            {
                hasFocus = true;
                ResumeEdit();
            }
        }

        protected override void OnLostFocus(RoutedEventArgs e)
        {
            base.OnLostFocus(e);

            object currentFocusedElement = FocusManager.GetFocusedElement();
            if (!TreeHelper.IsChildOf(this, currentFocusedElement as DependencyObject))
            {
                hasFocus = false;
                Validate(false);
            }
        }

        internal bool ResumeEdit()
        {
            if (this.CurrentDirtyCell != null)
                return CurrentDirtyCell.ResumeEdit();
            else if (this.CurrentDirtyItem != null)
            {
                FrameworkElement focusElement = FocusManager.GetFocusedElement() as FrameworkElement;
                if (ContainerItem.GetParentContainerItem(focusElement) != this.CurrentDirtyItem)
                    return this.CurrentDirtyItem.Focus();
            }

            return false;
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonDown(e);

            if (!hasFocus)
                ResumeEdit();
        }

        private void ItemsFocusProtect()
        {
            Panel itemsHost = this.ItemsHost;
            UIElementCollection itemsHostChildren = itemsHost.Children;
            foreach (ContainerItem item in itemsHostChildren)
                if ((item != CurrentDirtyItem) && (item != CurrentEditedItem))
                    item.FocusProtect(null);

            if (lastFocusControl != null)
                lastFocusControl.Visibility = Visibility.Visible;
        }

        private void ItemsFocusUnProtect()
        {
            Panel itemsHost = this.ItemsHost;
            UIElementCollection itemsHostChildren = itemsHost.Children;
            foreach (ContainerItem item in itemsHostChildren)
                if ((item != CurrentDirtyItem) && (item != CurrentEditedItem))
                    item.FocusUnProtect(null);

            if (lastFocusControl != null)
                lastFocusControl.Visibility = Visibility.Collapsed;
        }

        Control lastFocusControl;
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            lastFocusControl = this.GetTemplateChild("LastFocusControl") as Control;
        }
    }
}

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