DataGridCell.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / DataGridCell.cs / 1305600 / DataGridCell.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//--------------------------------------------------------------------------- 

using System; 
using System.Collections.ObjectModel; 
using System.ComponentModel;
using System.Diagnostics; 
using System.Globalization;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Data; 
using System.Windows.Input;
using System.Windows.Media; 
using System.Windows.Threading; 

namespace System.Windows.Controls 
{
    /// 
    ///     A control for displaying a cell of the DataGrid.
    ///  
    public class DataGridCell : ContentControl, IProvideDataGridColumn
    { 
        #region Constructors 

        ///  
        ///     Instantiates global information.
        /// 
        static DataGridCell()
        { 
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DataGridCell), new FrameworkPropertyMetadata(typeof(DataGridCell)));
            StyleProperty.OverrideMetadata(typeof(DataGridCell), new FrameworkPropertyMetadata(null, OnNotifyPropertyChanged, OnCoerceStyle)); 
            ClipProperty.OverrideMetadata(typeof(DataGridCell), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceClip))); 
            KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(DataGridCell), new FrameworkPropertyMetadata(KeyboardNavigationMode.Local));
 
            // Set SnapsToDevicePixels to true so that this element can draw grid lines.  The metadata options are so that the property value doesn't inherit down the tree from here.
            SnapsToDevicePixelsProperty.OverrideMetadata(typeof(DataGridCell), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsArrange));

            EventManager.RegisterClassHandler(typeof(DataGridCell), MouseLeftButtonDownEvent, new MouseButtonEventHandler(OnAnyMouseLeftButtonDownThunk), true); 

            IsMouseOverPropertyKey.OverrideMetadata(typeof(DataGridCell), new UIPropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged))); 
 
            EventManager.RegisterClassHandler(typeof(DataGridCell), LostFocusEvent, new RoutedEventHandler(OnAnyLostFocus), true);
            EventManager.RegisterClassHandler(typeof(DataGridCell), GotFocusEvent, new RoutedEventHandler(OnAnyGotFocus), true); 
        }

        /// 
        ///     Instantiates a new instance of this class. 
        /// 
        public DataGridCell() 
        { 
            _tracker = new ContainerTracking(this);
        } 

        #endregion

        #region Automation 

        protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer() 
        { 
            return new System.Windows.Automation.Peers.DataGridCellAutomationPeer(this);
        } 

        #endregion

        #region Cell Generation 

        ///  
        ///     Prepares a cell for use. 
        /// 
        ///  
        ///     Updates the column reference.
        ///     This overload computes the column index from the ItemContainerGenerator.
        /// 
        internal void PrepareCell(object item, ItemsControl cellsPresenter, DataGridRow ownerRow) 
        {
            PrepareCell(item, ownerRow, cellsPresenter.ItemContainerGenerator.IndexFromContainer(this)); 
        } 

        ///  
        ///     Prepares a cell for use.
        /// 
        /// 
        ///     Updates the column reference. 
        /// 
        internal void PrepareCell(object item, DataGridRow ownerRow, int index) 
        { 
            Debug.Assert(_owner == null || _owner == ownerRow, "_owner should be null before PrepareCell is called or the same value as the ownerRow.");
 
            _owner = ownerRow;

            DataGrid dataGrid = _owner.DataGridOwner;
            if (dataGrid != null) 
            {
                // The index of the container should correspond to the index of the column 
                if ((index >= 0) && (index < dataGrid.Columns.Count)) 
                {
                    // Retrieve the column definition and pass it to the cell container 
                    DataGridColumn column = dataGrid.Columns[index];
                    Column = column;
                    TabIndex = column.DisplayIndex;
                } 

                if (IsEditing) 
                { 
                    // If IsEditing was left on and this container was recycled, reset it here.
                    // Setting this property will result in BuildVisualTree being called. 
                    IsEditing = false;
                }
                else if ((Content as FrameworkElement) == null)
                { 
                    // If there isn't already a visual tree, then create one.
                    BuildVisualTree(); 
 
                    if (!NeedsVisualTree)
                    { 
                        Content = item;
                    }
                }
 
                // Update cell Selection
                bool isSelected = dataGrid.SelectedCellsInternal.Contains(this); 
                SyncIsSelected(isSelected); 
            }
 
            DataGridHelper.TransferProperty(this, StyleProperty);
            DataGridHelper.TransferProperty(this, IsReadOnlyProperty);
            CoerceValue(ClipProperty);
        } 

        ///  
        ///     Clears the cell of references. 
        /// 
        internal void ClearCell(DataGridRow ownerRow) 
        {
            Debug.Assert(_owner == ownerRow, "_owner should be the same as the DataGridRow that is clearing the cell.");
            _owner = null;
        } 

        ///  
        ///     Used by the DataGridRowGenerator owner to send notifications to the cell container. 
        /// 
        internal ContainerTracking Tracker 
        {
            get { return _tracker; }
        }
 
        #endregion
 
        #region Column Information 

        ///  
        ///     The column that defines how this cell should appear.
        /// 
        public DataGridColumn Column
        { 
            get { return (DataGridColumn)GetValue(ColumnProperty); }
            internal set { SetValue(ColumnPropertyKey, value); } 
        } 

        ///  
        ///     The DependencyPropertyKey that allows writing the Column property value.
        /// 
        private static readonly DependencyPropertyKey ColumnPropertyKey =
            DependencyProperty.RegisterReadOnly("Column", typeof(DataGridColumn), typeof(DataGridCell), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnColumnChanged))); 

        ///  
        ///     The DependencyProperty for the Columns property. 
        /// 
        public static readonly DependencyProperty ColumnProperty = ColumnPropertyKey.DependencyProperty; 

        /// 
        ///     Called when the Column property changes.
        ///     Calls the protected virtual OnColumnChanged. 
        /// 
        private static void OnColumnChanged(object sender, DependencyPropertyChangedEventArgs e) 
        { 
            DataGridCell cell = sender as DataGridCell;
            if (cell != null) 
            {
                cell.OnColumnChanged((DataGridColumn)e.OldValue, (DataGridColumn)e.NewValue);
            }
        } 

        ///  
        ///     Called due to the cell's column definition changing. 
        ///     Not called due to changes within the current column definition.
        ///  
        /// 
        ///     Coerces ContentTemplate and ContentTemplateSelector.
        /// 
        /// The old column definition. 
        /// The new column definition.
        protected virtual void OnColumnChanged(DataGridColumn oldColumn, DataGridColumn newColumn) 
        { 
            // We need to call BuildVisualTree after changing the column (PrepareCell does this).
            Content = null; 
            DataGridHelper.TransferProperty(this, StyleProperty);
            DataGridHelper.TransferProperty(this, IsReadOnlyProperty);
        }
 
        #endregion
 
        #region Notification Propagation 

        ///  
        ///     Notifies the Cell of a property change.
        /// 
        private static void OnNotifyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            ((DataGridCell)d).NotifyPropertyChanged(d, string.Empty, e, DataGridNotificationTarget.Cells);
        } 
 
        /// 
        ///     Cancels editing the current cell & notifies the cell of a change to IsReadOnly. 
        /// 
        private static void OnNotifyIsReadOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var cell = (DataGridCell)d; 
            var dataGrid = cell.DataGridOwner;
            if ((bool)e.NewValue && dataGrid != null) 
            { 
                dataGrid.CancelEdit(cell);
            } 

            // re-evalutate the BeginEdit command's CanExecute.
            CommandManager.InvalidateRequerySuggested();
 
            cell.NotifyPropertyChanged(d, string.Empty, e, DataGridNotificationTarget.Cells);
        } 
 
        /// 
        ///     General notification for DependencyProperty changes from the grid or from columns. 
        /// 
        internal void NotifyPropertyChanged(DependencyObject d, string propertyName, DependencyPropertyChangedEventArgs e, DataGridNotificationTarget target)
        {
            DataGridColumn column = d as DataGridColumn; 
            if ((column != null) && (column != Column))
            { 
                // This notification does not apply to this cell 
                return;
            } 

            // All the notifications which are to be handled by the cell
            if (DataGridHelper.ShouldNotifyCells(target))
            { 
                if (e.Property == DataGridColumn.WidthProperty)
                { 
                    DataGridHelper.OnColumnWidthChanged(this, e); 
                }
                else if (e.Property == DataGrid.CellStyleProperty || e.Property == DataGridColumn.CellStyleProperty || e.Property == StyleProperty) 
                {
                    DataGridHelper.TransferProperty(this, StyleProperty);
                }
                else if (e.Property == DataGrid.IsReadOnlyProperty || e.Property == DataGridColumn.IsReadOnlyProperty || e.Property == IsReadOnlyProperty) 
                {
                    DataGridHelper.TransferProperty(this, IsReadOnlyProperty); 
                } 
                else if (e.Property == DataGridColumn.DisplayIndexProperty)
                { 
                    TabIndex = column.DisplayIndex;
                }
                else if (e.Property == DataGrid.IsKeyboardFocusWithinProperty)
                { 
                    UpdateVisualState();
                } 
            } 

            // All the notifications which needs forward to columns 
            if (DataGridHelper.ShouldRefreshCellContent(target))
            {
                if (column != null && NeedsVisualTree)
                { 
                    if (!string.IsNullOrEmpty(propertyName))
                    { 
                        column.RefreshCellContent(this, propertyName); 
                    }
                    else if (e != null && e.Property != null) 
                    {
                        column.RefreshCellContent(this, e.Property.Name);
                    }
                } 
            }
        } 
 
        #endregion
 
        #region Style

        private static object OnCoerceStyle(DependencyObject d, object baseValue)
        { 
            var cell = d as DataGridCell;
            return DataGridHelper.GetCoercedTransferPropertyValue( 
                cell, 
                baseValue,
                StyleProperty, 
                cell.Column,
                DataGridColumn.CellStyleProperty,
                cell.DataGridOwner,
                DataGrid.CellStyleProperty); 
        }
 
        #endregion 

        #region Template 

        internal override void ChangeVisualState(bool useTransitions)
        {
            if (DataGridOwner == null) 
            {
                return; 
            } 

            // CommonStates 
            if (IsMouseOver)
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateMouseOver, VisualStates.StateNormal);
            } 
            else
            { 
                VisualStateManager.GoToState(this, VisualStates.StateNormal, useTransitions); 
            }
 
            // SelectionStates
            if (IsSelected)
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateSelected, VisualStates.StateUnselected); 
            }
            else 
            { 
                VisualStates.GoToState(this, useTransitions, VisualStates.StateUnselected);
            } 

            // FocusStates
            if (DataGridOwner.IsKeyboardFocusWithin)
            { 
                VisualStates.GoToState(this, useTransitions, VisualStates.StateFocused, VisualStates.StateUnfocused);
            } 
            else 
            {
                VisualStateManager.GoToState(this, VisualStates.StateUnfocused, useTransitions); 
            }

            // CurrentStates
            if (IsCurrent) 
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateCurrent, VisualStates.StateRegular); 
            } 
            else
            { 
                VisualStateManager.GoToState(this, VisualStates.StateRegular, useTransitions);
            }

            // Interaction states 
            if (IsEditing)
            { 
                VisualStates.GoToState(this, useTransitions, VisualStates.StateEditing, VisualStates.StateDisplay); 
            }
            else 
            {
                VisualStateManager.GoToState(this, VisualStates.StateDisplay, useTransitions);
            }
 
            base.ChangeVisualState(useTransitions);
        } 
 
        /// 
        ///     Builds a column's visual tree if not using templates. 
        /// 
        internal void BuildVisualTree()
        {
            if (NeedsVisualTree) 
            {
                var column = Column; 
                if (column != null) 
                {
                    // Work around a problem with BindingGroup not removing BindingExpressions. 
                    var row = RowOwner;
                    if (row != null)
                    {
                        var bindingGroup = row.BindingGroup; 
                        if (bindingGroup != null)
                        { 
                            RemoveBindingExpressions(bindingGroup, Content as DependencyObject); 
                        }
                    } 

                    // Ask the column to build a visual tree and
                    // hook the visual tree up through the Content property.
                    Content = column.BuildVisualTree(IsEditing, RowDataItem, this); 
                }
            } 
        } 

        private void RemoveBindingExpressions(BindingGroup bindingGroup, DependencyObject element) 
        {
            if (element == null)
                return; // no content, hence no bindings to remove
 
            var bindingExpressions = bindingGroup.BindingExpressions;
            for (int i = 0; i < bindingExpressions.Count; i++) 
            { 
                if (VisualTreeHelper.IsAncestorOf(element, bindingExpressions[i].TargetElement, typeof(DataGridCell)))
                { 
                    bindingExpressions.RemoveAt(i--);
                }
            }
        } 

        #endregion 
 
        #region Editing
 
        /// 
        ///     Whether the cell is in editing mode.
        /// 
        public bool IsEditing 
        {
            get { return (bool)GetValue(IsEditingProperty); } 
            set { SetValue(IsEditingProperty, value); } 
        }
 
        /// 
        ///     Represents the IsEditing property.
        /// 
        public static readonly DependencyProperty IsEditingProperty = DependencyProperty.Register("IsEditing", typeof(bool), typeof(DataGridCell), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsEditingChanged))); 

        private static void OnIsEditingChanged(object sender, DependencyPropertyChangedEventArgs e) 
        { 
            ((DataGridCell)sender).OnIsEditingChanged((bool)e.NewValue);
        } 

        /// 
        ///     Called when the value of IsEditing changes.
        ///  
        /// 
        ///     Coerces the value of ContentTemplate. 
        ///  
        /// The new value of IsEditing.
        protected virtual void OnIsEditingChanged(bool isEditing) 
        {
            if (IsKeyboardFocusWithin && !IsKeyboardFocused)
            {
                // Keep focus on the cell when flipping modes 
                Focus();
            } 
 
            // If templates aren't being used, then a new visual tree needs to be built.
            BuildVisualTree(); 
            UpdateVisualState();
        }

        internal void NotifyCurrentCellContainerChanged() 
        {
            UpdateVisualState(); 
        } 

        ///  
        ///     Whether the cell is the current cell.
        /// 
        private bool IsCurrent
        { 
            get
            { 
                var row = RowOwner; 
                var column = Column;
                if (row != null && column != null) 
                {
                    var dataGrid = row.DataGridOwner;
                    if (dataGrid != null)
                    { 
                        return dataGrid.CurrentItem == row.Item && dataGrid.CurrentColumn == column;
                    } 
                } 

                return false; 
            }
        }

        ///  
        ///     Whether the cell can be placed in edit mode.
        ///  
        public bool IsReadOnly 
        {
            get { return (bool)GetValue(IsReadOnlyProperty); } 
        }

        private static readonly DependencyPropertyKey IsReadOnlyPropertyKey =
            DependencyProperty.RegisterReadOnly("IsReadOnly", typeof(bool), typeof(DataGridCell), new FrameworkPropertyMetadata(false, OnNotifyIsReadOnlyChanged, OnCoerceIsReadOnly)); 

        ///  
        ///     The DependencyProperty for IsReadOnly. 
        /// 
        public static readonly DependencyProperty IsReadOnlyProperty = IsReadOnlyPropertyKey.DependencyProperty; 

        private static object OnCoerceIsReadOnly(DependencyObject d, object baseValue)
        {
            var cell = d as DataGridCell; 
            var column = cell.Column;
            var dataGrid = cell.DataGridOwner; 
 
            // We dont use the cell & 'baseValue' here because this property is read only on cell.
            // the column may coerce a default value to 'true', so we'll use it's effective value for IsReadOnly 
            // as the baseValue.
            return DataGridHelper.GetCoercedTransferPropertyValue(
                column,
                column.IsReadOnly, 
                DataGridColumn.IsReadOnlyProperty,
                dataGrid, 
                DataGrid.IsReadOnlyProperty); 
        }
 
        private static void OnAnyLostFocus(object sender, RoutedEventArgs e)
        {
            // Get the ancestor cell of old focused element.
            // Set DataGrid.FocusedCell to null, if the cell doesn't 
            // have keyboard focus.
            DataGridCell cell = DataGridHelper.FindVisualParent(e.OriginalSource as UIElement); 
            if (cell != null && cell == sender) 
            {
                DataGrid owner = cell.DataGridOwner; 
                if (owner != null && !cell.IsKeyboardFocusWithin && owner.FocusedCell == cell)
                {
                    owner.FocusedCell = null;
                } 
            }
        } 
 
        private static void OnAnyGotFocus(object sender, RoutedEventArgs e)
        { 
            DataGridCell cell = DataGridHelper.FindVisualParent(e.OriginalSource as UIElement);
            if (cell != null && cell == sender)
            {
                DataGrid owner = cell.DataGridOwner; 
                if (owner != null)
                { 
                    owner.FocusedCell = cell; 
                }
            } 
        }

        internal void BeginEdit(RoutedEventArgs e)
        { 
            Debug.Assert(!IsEditing, "Should not call BeginEdit when IsEditing is true.");
 
            IsEditing = true; 

            DataGridColumn column = Column; 
            if (column != null)
            {
                // Ask the column to store the original value
                column.BeginEdit(Content as FrameworkElement, e); 
            }
 
            RaisePreparingCellForEdit(e); 
        }
 
        internal void CancelEdit()
        {
            Debug.Assert(IsEditing, "Should not call CancelEdit when IsEditing is false.");
 
            DataGridColumn column = Column;
            if (column != null) 
            { 
                // Ask the column to restore the original value
                column.CancelEdit(Content as FrameworkElement); 
            }

            IsEditing = false;
        } 

        internal bool CommitEdit() 
        { 
            Debug.Assert(IsEditing, "Should not call CommitEdit when IsEditing is false.");
 
            bool validationPassed = true;
            DataGridColumn column = Column;
            if (column != null)
            { 
                // Ask the column to access the binding and update the data source
                // If validation fails, then remain in editing mode 
                validationPassed = column.CommitEdit(Content as FrameworkElement); 
            }
 
            if (validationPassed)
            {
                IsEditing = false;
            } 

            return validationPassed; 
        } 

        private void RaisePreparingCellForEdit(RoutedEventArgs editingEventArgs) 
        {
            DataGrid dataGridOwner = DataGridOwner;
            if (dataGridOwner != null)
            { 
                FrameworkElement currentEditingElement = EditingElement;
                DataGridPreparingCellForEditEventArgs preparingCellForEditEventArgs = new DataGridPreparingCellForEditEventArgs(Column, RowOwner, editingEventArgs, currentEditingElement); 
                dataGridOwner.OnPreparingCellForEdit(preparingCellForEditEventArgs); 
            }
        } 

        internal FrameworkElement EditingElement
        {
            get 
            {
                // The editing element was stored in the Content property. 
                return Content as FrameworkElement; 
            }
        } 

        #endregion

        #region Selection 

        ///  
        ///     Whether the cell is selected or not. 
        /// 
        public bool IsSelected 
        {
            get { return (bool)GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        } 

        ///  
        ///     Represents the IsSelected property. 
        /// 
        public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register("IsSelected", typeof(bool), typeof(DataGridCell), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsSelectedChanged))); 

        private static void OnIsSelectedChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            DataGridCell cell = (DataGridCell)sender; 
            bool isSelected = (bool)e.NewValue;
 
            // There is no reason to notify the DataGrid if IsSelected's value came 
            // from the DataGrid.
            if (!cell._syncingIsSelected) 
            {
                DataGrid dataGrid = cell.DataGridOwner;
                if (dataGrid != null)
                { 
                    // Notify the DataGrid that a cell's IsSelected property changed
                    // in case it was done programmatically instead of by the 
                    // DataGrid itself. 
                    dataGrid.CellIsSelectedChanged(cell, isSelected);
                } 
            }

            cell.RaiseSelectionChangedEvent(isSelected);
            cell.UpdateVisualState(); 
        }
 
        ///  
        ///     Used to synchronize IsSelected with the DataGrid.
        ///     Prevents unncessary notification back to the DataGrid. 
        /// 
        internal void SyncIsSelected(bool isSelected)
        {
            bool originalValue = _syncingIsSelected; 
            _syncingIsSelected = true;
            try 
            { 
                IsSelected = isSelected;
            } 
            finally
            {
                _syncingIsSelected = originalValue;
            } 
        }
 
        private void RaiseSelectionChangedEvent(bool isSelected) 
        {
            if (isSelected) 
            {
                OnSelected(new RoutedEventArgs(SelectedEvent, this));
            }
            else 
            {
                OnUnselected(new RoutedEventArgs(UnselectedEvent, this)); 
            } 
        }
 
        /// 
        ///     Raised when the item's IsSelected property becomes true.
        /// 
        public static readonly RoutedEvent SelectedEvent = EventManager.RegisterRoutedEvent("Selected", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(DataGridCell)); 

        ///  
        ///     Raised when the item's IsSelected property becomes true. 
        /// 
        public event RoutedEventHandler Selected 
        {
            add
            {
                AddHandler(SelectedEvent, value); 
            }
 
            remove 
            {
                RemoveHandler(SelectedEvent, value); 
            }
        }

        ///  
        ///     Called when IsSelected becomes true. Raises the Selected event.
        ///  
        /// Empty event arguments. 
        protected virtual void OnSelected(RoutedEventArgs e)
        { 
            RaiseEvent(e);
        }

        ///  
        ///     Raised when the item's IsSelected property becomes false.
        ///  
        public static readonly RoutedEvent UnselectedEvent = EventManager.RegisterRoutedEvent("Unselected", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(DataGridCell)); 

        ///  
        ///     Raised when the item's IsSelected property becomes false.
        /// 
        public event RoutedEventHandler Unselected
        { 
            add
            { 
                AddHandler(UnselectedEvent, value); 
            }
 
            remove
            {
                RemoveHandler(UnselectedEvent, value);
            } 
        }
 
        ///  
        ///     Called when IsSelected becomes false. Raises the Unselected event.
        ///  
        /// Empty event arguments.
        protected virtual void OnUnselected(RoutedEventArgs e)
        {
            RaiseEvent(e); 
        }
 
        #endregion 

        #region GridLines 

        // Different parts of the DataGrid draw different pieces of the GridLines.
        // Cells draw a single line on their right side.
 
        /// 
        ///     Measure.  This is overridden so that the cell can extend its size to account for a grid line on the right. 
        ///  
        protected override Size MeasureOverride(Size constraint)
        { 
            // Make space for the GridLine on the right:
            // Remove space from the constraint (since it implicitly includes the GridLine's thickness),
            // call the base implementation, and add the thickness back for the returned size.
            if (DataGridHelper.IsGridLineVisible(DataGridOwner, /*isHorizontal = */ false)) 
            {
                double thickness = DataGridOwner.VerticalGridLineThickness; 
                Size desiredSize = base.MeasureOverride(DataGridHelper.SubtractFromSize(constraint, thickness, /*height = */ false)); 
                desiredSize.Width += thickness;
                return desiredSize; 
            }
            else
            {
                return base.MeasureOverride(constraint); 
            }
        } 
 
        /// 
        ///     Arrange.  This is overriden so that the cell can position its content to account for a grid line on the right. 
        /// 
        /// Arrange size
        protected override Size ArrangeOverride(Size arrangeSize)
        { 
            // We don't need to adjust the Arrange position of the content.  By default it is arranged at 0,0 and we're
            // adding a line to the right.  All we have to do is compress and extend the size, just like Measure. 
            if (DataGridHelper.IsGridLineVisible(DataGridOwner, /*isHorizontal = */ false)) 
            {
                double thickness = DataGridOwner.VerticalGridLineThickness; 
                Size returnSize = base.ArrangeOverride(DataGridHelper.SubtractFromSize(arrangeSize, thickness, /*height = */ false));
                returnSize.Width += thickness;
                return returnSize;
            } 
            else
            { 
                return base.ArrangeOverride(arrangeSize); 
            }
        } 

        /// 
        ///     OnRender.  Overriden to draw a vertical line on the right.
        ///  
        /// 
        protected override void OnRender(DrawingContext drawingContext) 
        { 
            base.OnRender(drawingContext);
 
            if (DataGridHelper.IsGridLineVisible(DataGridOwner, /*isHorizontal = */ false))
            {
                double thickness = DataGridOwner.VerticalGridLineThickness;
                Rect rect = new Rect(new Size(thickness, RenderSize.Height)); 
                rect.X = RenderSize.Width - thickness;
 
                drawingContext.DrawRectangle(DataGridOwner.VerticalGridLinesBrush, null, rect); 
            }
        } 

        #endregion

        #region Input 

        private static void OnAnyMouseLeftButtonDownThunk(object sender, MouseButtonEventArgs e) 
        { 
            ((DataGridCell)sender).OnAnyMouseLeftButtonDown(e);
        } 

        /// 
        ///     The left mouse button was pressed
        ///  
        ///
        private void OnAnyMouseLeftButtonDown(MouseButtonEventArgs e) 
        { 
            bool focusWithin = IsKeyboardFocusWithin;
            bool isCtrlKeyPressed = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control; 
            if (focusWithin && !isCtrlKeyPressed && !e.Handled && !IsEditing && !IsReadOnly && IsSelected)
            {
                // The cell is focused and there are no other special selection gestures,
                // enter edit mode. 
                DataGrid dataGridOwner = DataGridOwner;
                if (dataGridOwner != null) 
                { 
                    // The cell was clicked, which means that other cells may
                    // need to be de-selected, let the DataGrid handle that. 
                    dataGridOwner.HandleSelectionForCellInput(this, /* startDragging = */ false, /* allowsExtendSelect = */ true, /* allowsMinimalSelect = */ false);

                    // Enter edit mode
                    dataGridOwner.BeginEdit(e); 
                    e.Handled = true;
                } 
            } 
            else if (!focusWithin || !IsSelected || isCtrlKeyPressed)
            { 
                if (!focusWithin)
                {
                    // The cell should receive focus on click
                    Focus(); 
                }
 
                DataGrid dataGridOwner = DataGridOwner; 
                if (dataGridOwner != null)
                { 
                    // Let the DataGrid process selection
                    dataGridOwner.HandleSelectionForCellInput(this, /* startDragging = */ Mouse.Captured == null, /* allowsExtendSelect = */ true, /* allowsMinimalSelect = */ true);
                }
 
                e.Handled = true;
            } 
#if PUBLIC_ONINPUT 
            else
            { 
                SendInputToColumn(e);
            }
#endif
        } 

        ///  
        ///     Reporting text composition. 
        /// 
        protected override void OnTextInput(TextCompositionEventArgs e) 
        {
            SendInputToColumn(e);
        }
 
        /// 
        ///     Reporting a key was pressed. 
        ///  
        protected override void OnKeyDown(KeyEventArgs e)
        { 
            SendInputToColumn(e);
        }

#if PUBLIC_ONINPUT 
        //
 
 

        ///  
        ///     Reporting a key was released
        /// 
        protected override void OnKeyUp(KeyEventArgs e)
        { 
            SendInputToColumn(e);
        } 
 
        /// 
        ///     Reporting the mouse button was released 
        /// 
        protected override void OnMouseUp(MouseButtonEventArgs e)
        {
            SendInputToColumn(e); 
        }
#endif 
 
        private void SendInputToColumn(InputEventArgs e)
        { 
            var column = Column;
            if (column != null)
            {
                column.OnInput(e); 
            }
        } 
 
        #endregion
 
        #region Frozen Columns

        /// 
        /// Coercion call back for clip property which ensures that the cell overlapping with frozen 
        /// column gets clipped appropriately.
        ///  
        ///  
        /// 
        ///  
        private static object OnCoerceClip(DependencyObject d, object baseValue)
        {
            DataGridCell cell = (DataGridCell)d;
            Geometry geometry = baseValue as Geometry; 
            Geometry frozenGeometry = DataGridHelper.GetFrozenClipForCell(cell);
            if (frozenGeometry != null) 
            { 
                if (geometry == null)
                { 
                    return frozenGeometry;
                }

                geometry = new CombinedGeometry(GeometryCombineMode.Intersect, geometry, frozenGeometry); 
            }
 
            return geometry; 
        }
 
        #endregion

        #region Helpers
 
        internal DataGrid DataGridOwner
        { 
            get 
            {
                if (_owner != null) 
                {
                    DataGrid dataGridOwner = _owner.DataGridOwner;
                    if (dataGridOwner == null)
                    { 
                        dataGridOwner = ItemsControl.ItemsControlFromItemContainer(_owner) as DataGrid;
                    } 
 
                    return dataGridOwner;
                } 

                return null;
            }
        } 

        private Panel ParentPanel 
        { 
            get
            { 
                return VisualParent as Panel;
            }
        }
 
        internal DataGridRow RowOwner
        { 
            get { return _owner; } 
        }
 
        internal object RowDataItem
        {
            get
            { 
                DataGridRow row = RowOwner;
                if (row != null) 
                { 
                    return row.Item;
                } 

                return DataContext;
            }
        } 

        private DataGridCellsPresenter CellsPresenter 
        { 
            get
            { 
                return ItemsControl.ItemsControlFromItemContainer(this) as DataGridCellsPresenter;
            }
        }
 
        private bool NeedsVisualTree
        { 
            get 
            {
                return (ContentTemplate == null) && (ContentTemplateSelector == null); 
            }
        }

        #endregion 

        #region Data 
 
        private DataGridRow _owner;
        private ContainerTracking _tracker; 
        private bool _syncingIsSelected;                    // Used to prevent unnecessary notifications

        #endregion
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//--------------------------------------------------------------------------- 

using System; 
using System.Collections.ObjectModel; 
using System.ComponentModel;
using System.Diagnostics; 
using System.Globalization;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Data; 
using System.Windows.Input;
using System.Windows.Media; 
using System.Windows.Threading; 

namespace System.Windows.Controls 
{
    /// 
    ///     A control for displaying a cell of the DataGrid.
    ///  
    public class DataGridCell : ContentControl, IProvideDataGridColumn
    { 
        #region Constructors 

        ///  
        ///     Instantiates global information.
        /// 
        static DataGridCell()
        { 
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DataGridCell), new FrameworkPropertyMetadata(typeof(DataGridCell)));
            StyleProperty.OverrideMetadata(typeof(DataGridCell), new FrameworkPropertyMetadata(null, OnNotifyPropertyChanged, OnCoerceStyle)); 
            ClipProperty.OverrideMetadata(typeof(DataGridCell), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceClip))); 
            KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(DataGridCell), new FrameworkPropertyMetadata(KeyboardNavigationMode.Local));
 
            // Set SnapsToDevicePixels to true so that this element can draw grid lines.  The metadata options are so that the property value doesn't inherit down the tree from here.
            SnapsToDevicePixelsProperty.OverrideMetadata(typeof(DataGridCell), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsArrange));

            EventManager.RegisterClassHandler(typeof(DataGridCell), MouseLeftButtonDownEvent, new MouseButtonEventHandler(OnAnyMouseLeftButtonDownThunk), true); 

            IsMouseOverPropertyKey.OverrideMetadata(typeof(DataGridCell), new UIPropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged))); 
 
            EventManager.RegisterClassHandler(typeof(DataGridCell), LostFocusEvent, new RoutedEventHandler(OnAnyLostFocus), true);
            EventManager.RegisterClassHandler(typeof(DataGridCell), GotFocusEvent, new RoutedEventHandler(OnAnyGotFocus), true); 
        }

        /// 
        ///     Instantiates a new instance of this class. 
        /// 
        public DataGridCell() 
        { 
            _tracker = new ContainerTracking(this);
        } 

        #endregion

        #region Automation 

        protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer() 
        { 
            return new System.Windows.Automation.Peers.DataGridCellAutomationPeer(this);
        } 

        #endregion

        #region Cell Generation 

        ///  
        ///     Prepares a cell for use. 
        /// 
        ///  
        ///     Updates the column reference.
        ///     This overload computes the column index from the ItemContainerGenerator.
        /// 
        internal void PrepareCell(object item, ItemsControl cellsPresenter, DataGridRow ownerRow) 
        {
            PrepareCell(item, ownerRow, cellsPresenter.ItemContainerGenerator.IndexFromContainer(this)); 
        } 

        ///  
        ///     Prepares a cell for use.
        /// 
        /// 
        ///     Updates the column reference. 
        /// 
        internal void PrepareCell(object item, DataGridRow ownerRow, int index) 
        { 
            Debug.Assert(_owner == null || _owner == ownerRow, "_owner should be null before PrepareCell is called or the same value as the ownerRow.");
 
            _owner = ownerRow;

            DataGrid dataGrid = _owner.DataGridOwner;
            if (dataGrid != null) 
            {
                // The index of the container should correspond to the index of the column 
                if ((index >= 0) && (index < dataGrid.Columns.Count)) 
                {
                    // Retrieve the column definition and pass it to the cell container 
                    DataGridColumn column = dataGrid.Columns[index];
                    Column = column;
                    TabIndex = column.DisplayIndex;
                } 

                if (IsEditing) 
                { 
                    // If IsEditing was left on and this container was recycled, reset it here.
                    // Setting this property will result in BuildVisualTree being called. 
                    IsEditing = false;
                }
                else if ((Content as FrameworkElement) == null)
                { 
                    // If there isn't already a visual tree, then create one.
                    BuildVisualTree(); 
 
                    if (!NeedsVisualTree)
                    { 
                        Content = item;
                    }
                }
 
                // Update cell Selection
                bool isSelected = dataGrid.SelectedCellsInternal.Contains(this); 
                SyncIsSelected(isSelected); 
            }
 
            DataGridHelper.TransferProperty(this, StyleProperty);
            DataGridHelper.TransferProperty(this, IsReadOnlyProperty);
            CoerceValue(ClipProperty);
        } 

        ///  
        ///     Clears the cell of references. 
        /// 
        internal void ClearCell(DataGridRow ownerRow) 
        {
            Debug.Assert(_owner == ownerRow, "_owner should be the same as the DataGridRow that is clearing the cell.");
            _owner = null;
        } 

        ///  
        ///     Used by the DataGridRowGenerator owner to send notifications to the cell container. 
        /// 
        internal ContainerTracking Tracker 
        {
            get { return _tracker; }
        }
 
        #endregion
 
        #region Column Information 

        ///  
        ///     The column that defines how this cell should appear.
        /// 
        public DataGridColumn Column
        { 
            get { return (DataGridColumn)GetValue(ColumnProperty); }
            internal set { SetValue(ColumnPropertyKey, value); } 
        } 

        ///  
        ///     The DependencyPropertyKey that allows writing the Column property value.
        /// 
        private static readonly DependencyPropertyKey ColumnPropertyKey =
            DependencyProperty.RegisterReadOnly("Column", typeof(DataGridColumn), typeof(DataGridCell), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnColumnChanged))); 

        ///  
        ///     The DependencyProperty for the Columns property. 
        /// 
        public static readonly DependencyProperty ColumnProperty = ColumnPropertyKey.DependencyProperty; 

        /// 
        ///     Called when the Column property changes.
        ///     Calls the protected virtual OnColumnChanged. 
        /// 
        private static void OnColumnChanged(object sender, DependencyPropertyChangedEventArgs e) 
        { 
            DataGridCell cell = sender as DataGridCell;
            if (cell != null) 
            {
                cell.OnColumnChanged((DataGridColumn)e.OldValue, (DataGridColumn)e.NewValue);
            }
        } 

        ///  
        ///     Called due to the cell's column definition changing. 
        ///     Not called due to changes within the current column definition.
        ///  
        /// 
        ///     Coerces ContentTemplate and ContentTemplateSelector.
        /// 
        /// The old column definition. 
        /// The new column definition.
        protected virtual void OnColumnChanged(DataGridColumn oldColumn, DataGridColumn newColumn) 
        { 
            // We need to call BuildVisualTree after changing the column (PrepareCell does this).
            Content = null; 
            DataGridHelper.TransferProperty(this, StyleProperty);
            DataGridHelper.TransferProperty(this, IsReadOnlyProperty);
        }
 
        #endregion
 
        #region Notification Propagation 

        ///  
        ///     Notifies the Cell of a property change.
        /// 
        private static void OnNotifyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            ((DataGridCell)d).NotifyPropertyChanged(d, string.Empty, e, DataGridNotificationTarget.Cells);
        } 
 
        /// 
        ///     Cancels editing the current cell & notifies the cell of a change to IsReadOnly. 
        /// 
        private static void OnNotifyIsReadOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var cell = (DataGridCell)d; 
            var dataGrid = cell.DataGridOwner;
            if ((bool)e.NewValue && dataGrid != null) 
            { 
                dataGrid.CancelEdit(cell);
            } 

            // re-evalutate the BeginEdit command's CanExecute.
            CommandManager.InvalidateRequerySuggested();
 
            cell.NotifyPropertyChanged(d, string.Empty, e, DataGridNotificationTarget.Cells);
        } 
 
        /// 
        ///     General notification for DependencyProperty changes from the grid or from columns. 
        /// 
        internal void NotifyPropertyChanged(DependencyObject d, string propertyName, DependencyPropertyChangedEventArgs e, DataGridNotificationTarget target)
        {
            DataGridColumn column = d as DataGridColumn; 
            if ((column != null) && (column != Column))
            { 
                // This notification does not apply to this cell 
                return;
            } 

            // All the notifications which are to be handled by the cell
            if (DataGridHelper.ShouldNotifyCells(target))
            { 
                if (e.Property == DataGridColumn.WidthProperty)
                { 
                    DataGridHelper.OnColumnWidthChanged(this, e); 
                }
                else if (e.Property == DataGrid.CellStyleProperty || e.Property == DataGridColumn.CellStyleProperty || e.Property == StyleProperty) 
                {
                    DataGridHelper.TransferProperty(this, StyleProperty);
                }
                else if (e.Property == DataGrid.IsReadOnlyProperty || e.Property == DataGridColumn.IsReadOnlyProperty || e.Property == IsReadOnlyProperty) 
                {
                    DataGridHelper.TransferProperty(this, IsReadOnlyProperty); 
                } 
                else if (e.Property == DataGridColumn.DisplayIndexProperty)
                { 
                    TabIndex = column.DisplayIndex;
                }
                else if (e.Property == DataGrid.IsKeyboardFocusWithinProperty)
                { 
                    UpdateVisualState();
                } 
            } 

            // All the notifications which needs forward to columns 
            if (DataGridHelper.ShouldRefreshCellContent(target))
            {
                if (column != null && NeedsVisualTree)
                { 
                    if (!string.IsNullOrEmpty(propertyName))
                    { 
                        column.RefreshCellContent(this, propertyName); 
                    }
                    else if (e != null && e.Property != null) 
                    {
                        column.RefreshCellContent(this, e.Property.Name);
                    }
                } 
            }
        } 
 
        #endregion
 
        #region Style

        private static object OnCoerceStyle(DependencyObject d, object baseValue)
        { 
            var cell = d as DataGridCell;
            return DataGridHelper.GetCoercedTransferPropertyValue( 
                cell, 
                baseValue,
                StyleProperty, 
                cell.Column,
                DataGridColumn.CellStyleProperty,
                cell.DataGridOwner,
                DataGrid.CellStyleProperty); 
        }
 
        #endregion 

        #region Template 

        internal override void ChangeVisualState(bool useTransitions)
        {
            if (DataGridOwner == null) 
            {
                return; 
            } 

            // CommonStates 
            if (IsMouseOver)
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateMouseOver, VisualStates.StateNormal);
            } 
            else
            { 
                VisualStateManager.GoToState(this, VisualStates.StateNormal, useTransitions); 
            }
 
            // SelectionStates
            if (IsSelected)
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateSelected, VisualStates.StateUnselected); 
            }
            else 
            { 
                VisualStates.GoToState(this, useTransitions, VisualStates.StateUnselected);
            } 

            // FocusStates
            if (DataGridOwner.IsKeyboardFocusWithin)
            { 
                VisualStates.GoToState(this, useTransitions, VisualStates.StateFocused, VisualStates.StateUnfocused);
            } 
            else 
            {
                VisualStateManager.GoToState(this, VisualStates.StateUnfocused, useTransitions); 
            }

            // CurrentStates
            if (IsCurrent) 
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateCurrent, VisualStates.StateRegular); 
            } 
            else
            { 
                VisualStateManager.GoToState(this, VisualStates.StateRegular, useTransitions);
            }

            // Interaction states 
            if (IsEditing)
            { 
                VisualStates.GoToState(this, useTransitions, VisualStates.StateEditing, VisualStates.StateDisplay); 
            }
            else 
            {
                VisualStateManager.GoToState(this, VisualStates.StateDisplay, useTransitions);
            }
 
            base.ChangeVisualState(useTransitions);
        } 
 
        /// 
        ///     Builds a column's visual tree if not using templates. 
        /// 
        internal void BuildVisualTree()
        {
            if (NeedsVisualTree) 
            {
                var column = Column; 
                if (column != null) 
                {
                    // Work around a problem with BindingGroup not removing BindingExpressions. 
                    var row = RowOwner;
                    if (row != null)
                    {
                        var bindingGroup = row.BindingGroup; 
                        if (bindingGroup != null)
                        { 
                            RemoveBindingExpressions(bindingGroup, Content as DependencyObject); 
                        }
                    } 

                    // Ask the column to build a visual tree and
                    // hook the visual tree up through the Content property.
                    Content = column.BuildVisualTree(IsEditing, RowDataItem, this); 
                }
            } 
        } 

        private void RemoveBindingExpressions(BindingGroup bindingGroup, DependencyObject element) 
        {
            if (element == null)
                return; // no content, hence no bindings to remove
 
            var bindingExpressions = bindingGroup.BindingExpressions;
            for (int i = 0; i < bindingExpressions.Count; i++) 
            { 
                if (VisualTreeHelper.IsAncestorOf(element, bindingExpressions[i].TargetElement, typeof(DataGridCell)))
                { 
                    bindingExpressions.RemoveAt(i--);
                }
            }
        } 

        #endregion 
 
        #region Editing
 
        /// 
        ///     Whether the cell is in editing mode.
        /// 
        public bool IsEditing 
        {
            get { return (bool)GetValue(IsEditingProperty); } 
            set { SetValue(IsEditingProperty, value); } 
        }
 
        /// 
        ///     Represents the IsEditing property.
        /// 
        public static readonly DependencyProperty IsEditingProperty = DependencyProperty.Register("IsEditing", typeof(bool), typeof(DataGridCell), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsEditingChanged))); 

        private static void OnIsEditingChanged(object sender, DependencyPropertyChangedEventArgs e) 
        { 
            ((DataGridCell)sender).OnIsEditingChanged((bool)e.NewValue);
        } 

        /// 
        ///     Called when the value of IsEditing changes.
        ///  
        /// 
        ///     Coerces the value of ContentTemplate. 
        ///  
        /// The new value of IsEditing.
        protected virtual void OnIsEditingChanged(bool isEditing) 
        {
            if (IsKeyboardFocusWithin && !IsKeyboardFocused)
            {
                // Keep focus on the cell when flipping modes 
                Focus();
            } 
 
            // If templates aren't being used, then a new visual tree needs to be built.
            BuildVisualTree(); 
            UpdateVisualState();
        }

        internal void NotifyCurrentCellContainerChanged() 
        {
            UpdateVisualState(); 
        } 

        ///  
        ///     Whether the cell is the current cell.
        /// 
        private bool IsCurrent
        { 
            get
            { 
                var row = RowOwner; 
                var column = Column;
                if (row != null && column != null) 
                {
                    var dataGrid = row.DataGridOwner;
                    if (dataGrid != null)
                    { 
                        return dataGrid.CurrentItem == row.Item && dataGrid.CurrentColumn == column;
                    } 
                } 

                return false; 
            }
        }

        ///  
        ///     Whether the cell can be placed in edit mode.
        ///  
        public bool IsReadOnly 
        {
            get { return (bool)GetValue(IsReadOnlyProperty); } 
        }

        private static readonly DependencyPropertyKey IsReadOnlyPropertyKey =
            DependencyProperty.RegisterReadOnly("IsReadOnly", typeof(bool), typeof(DataGridCell), new FrameworkPropertyMetadata(false, OnNotifyIsReadOnlyChanged, OnCoerceIsReadOnly)); 

        ///  
        ///     The DependencyProperty for IsReadOnly. 
        /// 
        public static readonly DependencyProperty IsReadOnlyProperty = IsReadOnlyPropertyKey.DependencyProperty; 

        private static object OnCoerceIsReadOnly(DependencyObject d, object baseValue)
        {
            var cell = d as DataGridCell; 
            var column = cell.Column;
            var dataGrid = cell.DataGridOwner; 
 
            // We dont use the cell & 'baseValue' here because this property is read only on cell.
            // the column may coerce a default value to 'true', so we'll use it's effective value for IsReadOnly 
            // as the baseValue.
            return DataGridHelper.GetCoercedTransferPropertyValue(
                column,
                column.IsReadOnly, 
                DataGridColumn.IsReadOnlyProperty,
                dataGrid, 
                DataGrid.IsReadOnlyProperty); 
        }
 
        private static void OnAnyLostFocus(object sender, RoutedEventArgs e)
        {
            // Get the ancestor cell of old focused element.
            // Set DataGrid.FocusedCell to null, if the cell doesn't 
            // have keyboard focus.
            DataGridCell cell = DataGridHelper.FindVisualParent(e.OriginalSource as UIElement); 
            if (cell != null && cell == sender) 
            {
                DataGrid owner = cell.DataGridOwner; 
                if (owner != null && !cell.IsKeyboardFocusWithin && owner.FocusedCell == cell)
                {
                    owner.FocusedCell = null;
                } 
            }
        } 
 
        private static void OnAnyGotFocus(object sender, RoutedEventArgs e)
        { 
            DataGridCell cell = DataGridHelper.FindVisualParent(e.OriginalSource as UIElement);
            if (cell != null && cell == sender)
            {
                DataGrid owner = cell.DataGridOwner; 
                if (owner != null)
                { 
                    owner.FocusedCell = cell; 
                }
            } 
        }

        internal void BeginEdit(RoutedEventArgs e)
        { 
            Debug.Assert(!IsEditing, "Should not call BeginEdit when IsEditing is true.");
 
            IsEditing = true; 

            DataGridColumn column = Column; 
            if (column != null)
            {
                // Ask the column to store the original value
                column.BeginEdit(Content as FrameworkElement, e); 
            }
 
            RaisePreparingCellForEdit(e); 
        }
 
        internal void CancelEdit()
        {
            Debug.Assert(IsEditing, "Should not call CancelEdit when IsEditing is false.");
 
            DataGridColumn column = Column;
            if (column != null) 
            { 
                // Ask the column to restore the original value
                column.CancelEdit(Content as FrameworkElement); 
            }

            IsEditing = false;
        } 

        internal bool CommitEdit() 
        { 
            Debug.Assert(IsEditing, "Should not call CommitEdit when IsEditing is false.");
 
            bool validationPassed = true;
            DataGridColumn column = Column;
            if (column != null)
            { 
                // Ask the column to access the binding and update the data source
                // If validation fails, then remain in editing mode 
                validationPassed = column.CommitEdit(Content as FrameworkElement); 
            }
 
            if (validationPassed)
            {
                IsEditing = false;
            } 

            return validationPassed; 
        } 

        private void RaisePreparingCellForEdit(RoutedEventArgs editingEventArgs) 
        {
            DataGrid dataGridOwner = DataGridOwner;
            if (dataGridOwner != null)
            { 
                FrameworkElement currentEditingElement = EditingElement;
                DataGridPreparingCellForEditEventArgs preparingCellForEditEventArgs = new DataGridPreparingCellForEditEventArgs(Column, RowOwner, editingEventArgs, currentEditingElement); 
                dataGridOwner.OnPreparingCellForEdit(preparingCellForEditEventArgs); 
            }
        } 

        internal FrameworkElement EditingElement
        {
            get 
            {
                // The editing element was stored in the Content property. 
                return Content as FrameworkElement; 
            }
        } 

        #endregion

        #region Selection 

        ///  
        ///     Whether the cell is selected or not. 
        /// 
        public bool IsSelected 
        {
            get { return (bool)GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        } 

        ///  
        ///     Represents the IsSelected property. 
        /// 
        public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register("IsSelected", typeof(bool), typeof(DataGridCell), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsSelectedChanged))); 

        private static void OnIsSelectedChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            DataGridCell cell = (DataGridCell)sender; 
            bool isSelected = (bool)e.NewValue;
 
            // There is no reason to notify the DataGrid if IsSelected's value came 
            // from the DataGrid.
            if (!cell._syncingIsSelected) 
            {
                DataGrid dataGrid = cell.DataGridOwner;
                if (dataGrid != null)
                { 
                    // Notify the DataGrid that a cell's IsSelected property changed
                    // in case it was done programmatically instead of by the 
                    // DataGrid itself. 
                    dataGrid.CellIsSelectedChanged(cell, isSelected);
                } 
            }

            cell.RaiseSelectionChangedEvent(isSelected);
            cell.UpdateVisualState(); 
        }
 
        ///  
        ///     Used to synchronize IsSelected with the DataGrid.
        ///     Prevents unncessary notification back to the DataGrid. 
        /// 
        internal void SyncIsSelected(bool isSelected)
        {
            bool originalValue = _syncingIsSelected; 
            _syncingIsSelected = true;
            try 
            { 
                IsSelected = isSelected;
            } 
            finally
            {
                _syncingIsSelected = originalValue;
            } 
        }
 
        private void RaiseSelectionChangedEvent(bool isSelected) 
        {
            if (isSelected) 
            {
                OnSelected(new RoutedEventArgs(SelectedEvent, this));
            }
            else 
            {
                OnUnselected(new RoutedEventArgs(UnselectedEvent, this)); 
            } 
        }
 
        /// 
        ///     Raised when the item's IsSelected property becomes true.
        /// 
        public static readonly RoutedEvent SelectedEvent = EventManager.RegisterRoutedEvent("Selected", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(DataGridCell)); 

        ///  
        ///     Raised when the item's IsSelected property becomes true. 
        /// 
        public event RoutedEventHandler Selected 
        {
            add
            {
                AddHandler(SelectedEvent, value); 
            }
 
            remove 
            {
                RemoveHandler(SelectedEvent, value); 
            }
        }

        ///  
        ///     Called when IsSelected becomes true. Raises the Selected event.
        ///  
        /// Empty event arguments. 
        protected virtual void OnSelected(RoutedEventArgs e)
        { 
            RaiseEvent(e);
        }

        ///  
        ///     Raised when the item's IsSelected property becomes false.
        ///  
        public static readonly RoutedEvent UnselectedEvent = EventManager.RegisterRoutedEvent("Unselected", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(DataGridCell)); 

        ///  
        ///     Raised when the item's IsSelected property becomes false.
        /// 
        public event RoutedEventHandler Unselected
        { 
            add
            { 
                AddHandler(UnselectedEvent, value); 
            }
 
            remove
            {
                RemoveHandler(UnselectedEvent, value);
            } 
        }
 
        ///  
        ///     Called when IsSelected becomes false. Raises the Unselected event.
        ///  
        /// Empty event arguments.
        protected virtual void OnUnselected(RoutedEventArgs e)
        {
            RaiseEvent(e); 
        }
 
        #endregion 

        #region GridLines 

        // Different parts of the DataGrid draw different pieces of the GridLines.
        // Cells draw a single line on their right side.
 
        /// 
        ///     Measure.  This is overridden so that the cell can extend its size to account for a grid line on the right. 
        ///  
        protected override Size MeasureOverride(Size constraint)
        { 
            // Make space for the GridLine on the right:
            // Remove space from the constraint (since it implicitly includes the GridLine's thickness),
            // call the base implementation, and add the thickness back for the returned size.
            if (DataGridHelper.IsGridLineVisible(DataGridOwner, /*isHorizontal = */ false)) 
            {
                double thickness = DataGridOwner.VerticalGridLineThickness; 
                Size desiredSize = base.MeasureOverride(DataGridHelper.SubtractFromSize(constraint, thickness, /*height = */ false)); 
                desiredSize.Width += thickness;
                return desiredSize; 
            }
            else
            {
                return base.MeasureOverride(constraint); 
            }
        } 
 
        /// 
        ///     Arrange.  This is overriden so that the cell can position its content to account for a grid line on the right. 
        /// 
        /// Arrange size
        protected override Size ArrangeOverride(Size arrangeSize)
        { 
            // We don't need to adjust the Arrange position of the content.  By default it is arranged at 0,0 and we're
            // adding a line to the right.  All we have to do is compress and extend the size, just like Measure. 
            if (DataGridHelper.IsGridLineVisible(DataGridOwner, /*isHorizontal = */ false)) 
            {
                double thickness = DataGridOwner.VerticalGridLineThickness; 
                Size returnSize = base.ArrangeOverride(DataGridHelper.SubtractFromSize(arrangeSize, thickness, /*height = */ false));
                returnSize.Width += thickness;
                return returnSize;
            } 
            else
            { 
                return base.ArrangeOverride(arrangeSize); 
            }
        } 

        /// 
        ///     OnRender.  Overriden to draw a vertical line on the right.
        ///  
        /// 
        protected override void OnRender(DrawingContext drawingContext) 
        { 
            base.OnRender(drawingContext);
 
            if (DataGridHelper.IsGridLineVisible(DataGridOwner, /*isHorizontal = */ false))
            {
                double thickness = DataGridOwner.VerticalGridLineThickness;
                Rect rect = new Rect(new Size(thickness, RenderSize.Height)); 
                rect.X = RenderSize.Width - thickness;
 
                drawingContext.DrawRectangle(DataGridOwner.VerticalGridLinesBrush, null, rect); 
            }
        } 

        #endregion

        #region Input 

        private static void OnAnyMouseLeftButtonDownThunk(object sender, MouseButtonEventArgs e) 
        { 
            ((DataGridCell)sender).OnAnyMouseLeftButtonDown(e);
        } 

        /// 
        ///     The left mouse button was pressed
        ///  
        ///
        private void OnAnyMouseLeftButtonDown(MouseButtonEventArgs e) 
        { 
            bool focusWithin = IsKeyboardFocusWithin;
            bool isCtrlKeyPressed = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control; 
            if (focusWithin && !isCtrlKeyPressed && !e.Handled && !IsEditing && !IsReadOnly && IsSelected)
            {
                // The cell is focused and there are no other special selection gestures,
                // enter edit mode. 
                DataGrid dataGridOwner = DataGridOwner;
                if (dataGridOwner != null) 
                { 
                    // The cell was clicked, which means that other cells may
                    // need to be de-selected, let the DataGrid handle that. 
                    dataGridOwner.HandleSelectionForCellInput(this, /* startDragging = */ false, /* allowsExtendSelect = */ true, /* allowsMinimalSelect = */ false);

                    // Enter edit mode
                    dataGridOwner.BeginEdit(e); 
                    e.Handled = true;
                } 
            } 
            else if (!focusWithin || !IsSelected || isCtrlKeyPressed)
            { 
                if (!focusWithin)
                {
                    // The cell should receive focus on click
                    Focus(); 
                }
 
                DataGrid dataGridOwner = DataGridOwner; 
                if (dataGridOwner != null)
                { 
                    // Let the DataGrid process selection
                    dataGridOwner.HandleSelectionForCellInput(this, /* startDragging = */ Mouse.Captured == null, /* allowsExtendSelect = */ true, /* allowsMinimalSelect = */ true);
                }
 
                e.Handled = true;
            } 
#if PUBLIC_ONINPUT 
            else
            { 
                SendInputToColumn(e);
            }
#endif
        } 

        ///  
        ///     Reporting text composition. 
        /// 
        protected override void OnTextInput(TextCompositionEventArgs e) 
        {
            SendInputToColumn(e);
        }
 
        /// 
        ///     Reporting a key was pressed. 
        ///  
        protected override void OnKeyDown(KeyEventArgs e)
        { 
            SendInputToColumn(e);
        }

#if PUBLIC_ONINPUT 
        //
 
 

        ///  
        ///     Reporting a key was released
        /// 
        protected override void OnKeyUp(KeyEventArgs e)
        { 
            SendInputToColumn(e);
        } 
 
        /// 
        ///     Reporting the mouse button was released 
        /// 
        protected override void OnMouseUp(MouseButtonEventArgs e)
        {
            SendInputToColumn(e); 
        }
#endif 
 
        private void SendInputToColumn(InputEventArgs e)
        { 
            var column = Column;
            if (column != null)
            {
                column.OnInput(e); 
            }
        } 
 
        #endregion
 
        #region Frozen Columns

        /// 
        /// Coercion call back for clip property which ensures that the cell overlapping with frozen 
        /// column gets clipped appropriately.
        ///  
        ///  
        /// 
        ///  
        private static object OnCoerceClip(DependencyObject d, object baseValue)
        {
            DataGridCell cell = (DataGridCell)d;
            Geometry geometry = baseValue as Geometry; 
            Geometry frozenGeometry = DataGridHelper.GetFrozenClipForCell(cell);
            if (frozenGeometry != null) 
            { 
                if (geometry == null)
                { 
                    return frozenGeometry;
                }

                geometry = new CombinedGeometry(GeometryCombineMode.Intersect, geometry, frozenGeometry); 
            }
 
            return geometry; 
        }
 
        #endregion

        #region Helpers
 
        internal DataGrid DataGridOwner
        { 
            get 
            {
                if (_owner != null) 
                {
                    DataGrid dataGridOwner = _owner.DataGridOwner;
                    if (dataGridOwner == null)
                    { 
                        dataGridOwner = ItemsControl.ItemsControlFromItemContainer(_owner) as DataGrid;
                    } 
 
                    return dataGridOwner;
                } 

                return null;
            }
        } 

        private Panel ParentPanel 
        { 
            get
            { 
                return VisualParent as Panel;
            }
        }
 
        internal DataGridRow RowOwner
        { 
            get { return _owner; } 
        }
 
        internal object RowDataItem
        {
            get
            { 
                DataGridRow row = RowOwner;
                if (row != null) 
                { 
                    return row.Item;
                } 

                return DataContext;
            }
        } 

        private DataGridCellsPresenter CellsPresenter 
        { 
            get
            { 
                return ItemsControl.ItemsControlFromItemContainer(this) as DataGridCellsPresenter;
            }
        }
 
        private bool NeedsVisualTree
        { 
            get 
            {
                return (ContentTemplate == null) && (ContentTemplateSelector == null); 
            }
        }

        #endregion 

        #region Data 
 
        private DataGridRow _owner;
        private ContainerTracking _tracker; 
        private bool _syncingIsSelected;                    // Used to prevent unnecessary notifications

        #endregion
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK