context: //---------------------------------------------------------------------------
  //
  // 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;
  using System.Windows.Controls.Primitives;
  using System.Windows.Data;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Threading;
  using Microsoft.Windows.Controls.Primitives;
  
  namespace Microsoft.Windows.Controls
  {
      /// <summary>
      ///     A control for displaying a cell of the DataGrid.
      /// </summary>
      public class DataGridCell : ContentControl, IProvideDataGridColumn
      {
          #region Constructors
  
          /// <summary>
          ///     Instantiates global information.
          /// </summary>
          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);
              
              EventManager.RegisterClassHandler(typeof(DataGridCell), LostFocusEvent, new RoutedEventHandler(OnAnyLostFocus), true);
              EventManager.RegisterClassHandler(typeof(DataGridCell), GotFocusEvent, new RoutedEventHandler(OnAnyGotFocus), true);
          }
  
          /// <summary>
          ///     Instantiates a new instance of this class.
          /// </summary>
          public DataGridCell()
          {
              _tracker = new ContainerTracking<DataGridCell>(this);
          }
  
          #endregion
  
          #region Automation
  
          protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
          {
              return new Microsoft.Windows.Automation.Peers.DataGridCellAutomationPeer(this);
          }
  
          #endregion
  
          #region Cell Generation
  
          /// <summary>
          ///     Prepares a cell for use.
          /// </summary>
          /// <remarks>
          ///     Updates the column reference.
          ///     This overload computes the column index from the ItemContainerGenerator.
          /// </remarks>
          internal void PrepareCell(object item, ItemsControl cellsPresenter, DataGridRow ownerRow)
          {
              PrepareCell(item, ownerRow, cellsPresenter.ItemContainerGenerator.IndexFromContainer(this));
          }
  
          /// <summary>
          ///     Prepares a cell for use.
          /// </summary>
          /// <remarks>
          ///     Updates the column reference.
          /// </remarks>
          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);
          }
  
          /// <summary>
          ///     Clears the cell of references.
          /// </summary>
          internal void ClearCell(DataGridRow ownerRow)
          {
              Debug.Assert(_owner == ownerRow, "_owner should be the same as the DataGridRow that is clearing the cell.");
              _owner = null;
          }
  
          /// <summary>
          ///     Used by the DataGridRowGenerator owner to send notifications to the cell container.
          /// </summary>
          internal ContainerTracking<DataGridCell> Tracker
          {
              get { return _tracker; }
          }
  
          #endregion
  
          #region Column Information
  
          /// <summary>
          ///     The column that defines how this cell should appear.
          /// </summary>
          public DataGridColumn Column
          {
              get { return (DataGridColumn)GetValue(ColumnProperty); }
              internal set { SetValue(ColumnPropertyKey, value); }
          }
  
          /// <summary>
          ///     The DependencyPropertyKey that allows writing the Column property value.
          /// </summary>
          private static readonly DependencyPropertyKey ColumnPropertyKey =
              DependencyProperty.RegisterReadOnly("Column", typeof(DataGridColumn), typeof(DataGridCell), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnColumnChanged)));
  
          /// <summary>
          ///     The DependencyProperty for the Columns property.
          /// </summary>
          public static readonly DependencyProperty ColumnProperty = ColumnPropertyKey.DependencyProperty;
  
          /// <summary>
          ///     Called when the Column property changes.
          ///     Calls the protected virtual OnColumnChanged.
          /// </summary>
          private static void OnColumnChanged(object sender, DependencyPropertyChangedEventArgs e)
          {
              DataGridCell cell = sender as DataGridCell;
              if (cell != null)
              {
                  cell.OnColumnChanged((DataGridColumn)e.OldValue, (DataGridColumn)e.NewValue);
              }
          }
  
          /// <summary>
          ///     Called due to the cell's column definition changing.
          ///     Not called due to changes within the current column definition.
          /// </summary>
          /// <remarks>
          ///     Coerces ContentTemplate and ContentTemplateSelector.
          /// </remarks>
          /// <param name="oldColumn">The old column definition.</param>
          /// <param name="newColumn">The new column definition.</param>
          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
  
          /// <summary>
          ///     Notifies the Cell of a property change.
          /// </summary>
          private static void OnNotifyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
          {
              ((DataGridCell)d).NotifyPropertyChanged(d, string.Empty, e, NotificationTarget.Cells);
          }
  
          /// <summary>
          ///     Cancels editing the current cell & notifies the cell of a change to IsReadOnly.
          /// </summary>
          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, NotificationTarget.Cells);
          }
  
          /// <summary>
          ///     General notification for DependencyProperty changes from the grid or from columns.
          /// </summary>
          internal void NotifyPropertyChanged(DependencyObject d, string propertyName, DependencyPropertyChangedEventArgs e, NotificationTarget 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;
                  }
              }
  
              // 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
  
          /// <summary>
          ///     Builds a column's visual tree if not using templates.
          /// </summary>
          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;
  
gt:                         if (bindingGroup != null)