PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 1ms

/class/Microsoft.SilverlightControls/SDKControls/Data/src/DataGrid/DataGrid.xaml.cs

http://github.com/mono/moon
C# | 6063 lines | 4566 code | 784 blank | 713 comment | 1160 complexity | ed3fbb8e759d43c44a097ec2760d700b MD5 | raw file
Possible License(s): CC-BY-SA-3.0, MIT, LGPL-2.1, MPL-2.0-no-copyleft-exception, GPL-3.0
  1. // (c) Copyright Microsoft Corporation.
  2. // This source is subject to the Microsoft Public License (Ms-PL).
  3. // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
  4. // All other rights reserved.
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using System.Collections.ObjectModel;
  8. using System.Diagnostics;
  9. using System.Diagnostics.CodeAnalysis;
  10. using System.Windows.Automation.Peers;
  11. using System.Windows.Controls.Primitives;
  12. using System.Windows.Input;
  13. using System.Windows.Media;
  14. namespace System.Windows.Controls
  15. {
  16. [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
  17. /// <summary>
  18. /// Displays data in a customizable grid.
  19. /// </summary>
  20. [TemplatePart(Name = DataGrid.DATAGRID_elementRowsPresenterName, Type = typeof(DataGridRowsPresenter))]
  21. [TemplatePart(Name = DataGrid.DATAGRID_elementColumnHeadersPresenterName, Type = typeof(DataGridColumnHeadersPresenter))]
  22. [TemplatePart(Name = DataGrid.DATAGRID_elementFrozenColumnScrollBarSpacerName, Type = typeof(FrameworkElement))]
  23. [TemplatePart(Name = DataGrid.DATAGRID_elementHorizontalScrollbarName, Type = typeof(ScrollBar))]
  24. [TemplatePart(Name = DataGrid.DATAGRID_elementVerticalScrollbarName, Type = typeof(ScrollBar))]
  25. public partial class DataGrid : Control
  26. {
  27. #region Constants
  28. private const string DATAGRID_elementRowsPresenterName = "RowsPresenter";
  29. private const string DATAGRID_elementColumnHeadersPresenterName = "ColumnHeadersPresenter";
  30. private const string DATAGRID_elementFrozenColumnScrollBarSpacerName = "FrozenColumnScrollBarSpacer";
  31. private const string DATAGRID_elementHorizontalScrollbarName = "HorizontalScrollbar";
  32. private const string DATAGRID_elementRowHeadersPresenterName = "RowHeadersPresenter";
  33. private const string DATAGRID_elementTopLeftCornerHeaderName = "TopLeftCornerHeader";
  34. private const string DATAGRID_elementTopRightCornerHeaderName = "TopRightCornerHeader";
  35. private const string DATAGRID_elementVerticalScrollbarName = "VerticalScrollbar";
  36. private const bool DATAGRID_defaultAutoGenerateColumns = true;
  37. internal const bool DATAGRID_defaultCanUserReorderColumns = true;
  38. internal const bool DATAGRID_defaultCanUserResizeColumns = true;
  39. internal const bool DATAGRID_defaultCanUserSortColumns = true;
  40. private const DataGridRowDetailsVisibilityMode DATAGRID_defaultRowDetailsVisibility = DataGridRowDetailsVisibilityMode.VisibleWhenSelected;
  41. private const DataGridSelectionMode DATAGRID_defaultSelectionMode = DataGridSelectionMode.Extended;
  42. private const double DATAGRID_horizontalGridLinesThickness = 1;
  43. private const double DATAGRID_minimumRowHeaderWidth = 4;
  44. private const double DATAGRID_minimumColumnHeaderHeight = 4;
  45. private const double DATAGRID_maxHeadersThickness = 32768;
  46. private const double DATAGRID_defaultRowHeight = 22;
  47. private const double DATAGRID_defaultMinColumnWidth = 20;
  48. private const double DATAGRID_defaultMaxColumnWidth = double.PositiveInfinity;
  49. #endregion Constants
  50. #region Data
  51. // DataGrid Template Parts
  52. private DataGridRowsPresenter _rowsPresenter;
  53. private DataGridColumnHeadersPresenter _columnHeadersPresenter;
  54. private ScrollBar _hScrollBar;
  55. private ScrollBar _vScrollBar;
  56. private List<object> _addedSelectedItems;
  57. private byte _autoGeneratingColumnOperationCount;
  58. private Popup _columnDropLocationIndicatorPopup;
  59. private Control _columnDropLocationIndicator;
  60. private DataGridCellCoordinates _currentCellCoordinates;
  61. private List<DataGridCell> _editingBoundCells;
  62. private int _editingElementGotFocusListeners;
  63. private int _editingElementLostFocusListeners; // Number of subscribers for the LostFocus event of the element of a edited cell in a column
  64. private int _editingColumnIndex;
  65. private DataGridRow _editingRow;
  66. private RoutedEventArgs _editingEventArgs;
  67. private Control _editingTemplateControl; // Control that has focus inside a template column
  68. private bool _focusEditingControl;
  69. private DataGridRow _focusedRow;
  70. private FrameworkElement _frozenColumnScrollBarSpacer;
  71. // the sum of the widths in pixels of the scrolling columns preceding
  72. // the first displayed scrolling column
  73. private double _horizontalOffset;
  74. private bool _ignoreNextScrollBarsLayout;
  75. private byte _horizontalScrollChangesIgnored;
  76. // Nth row of rows 0..N that make up the RowHeightEstimate
  77. private int _lastEstimatedRow;
  78. private List<DataGridRow> _loadedRows;
  79. // prevents reentry into the VerticalScroll event handler
  80. private bool _makeFirstDisplayedCellCurrentCellPending;
  81. private bool _measured;
  82. private int? _mouseOverRowIndex; // -1 is used for the 'new row'
  83. // the number of pixels of the firstDisplayedScrollingCol which are not displayed
  84. private double _negHorizontalOffset;
  85. // the number of pixels of DisplayData.FirstDisplayedScrollingRow which are not displayed
  86. //
  87. private int _noSelectionChangeCount;
  88. private List<object> _removedSelectedItems;
  89. private double _rowHeaderDesiredWidth;
  90. private DataGridSelectedItemsCollection _selectedItems;
  91. private bool _selectionChanged;
  92. private IndexToValueTable<Visibility> _showDetailsTable;
  93. private bool _temporarilyResetCurrentCell;
  94. private ContentControl _topLeftCornerHeader;
  95. private ContentControl _topRightCornerHeader;
  96. private object _uneditedValue; // Represents the original current cell value at the time it enters editing mode.
  97. private byte _verticalScrollChangesIgnored;
  98. // An approximation of the sum of the heights in pixels of the scrolling rows preceding
  99. // the first displayed scrolling row. Since the scrolled off rows are discarded, the grid
  100. // does not know their actual height. The heights used for the approximation are the ones
  101. // set as the rows were scrolled off.
  102. private double _verticalOffset;
  103. #endregion Data
  104. #region Events
  105. public event EventHandler<DataGridAutoGeneratingColumnEventArgs> AutoGeneratingColumn;
  106. public event EventHandler<DataGridBeginningEditEventArgs> BeginningEdit;
  107. //
  108. public event EventHandler<DataGridColumnEventArgs> ColumnDisplayIndexChanged;
  109. public event EventHandler<DragStartedEventArgs> ColumnHeaderDragStarted;
  110. public event EventHandler<DragDeltaEventArgs> ColumnHeaderDragDelta;
  111. public event EventHandler<DragCompletedEventArgs> ColumnHeaderDragCompleted;
  112. /// <summary>
  113. /// Raised when column reordering ends, to allow subscribers to clean up.
  114. /// </summary>
  115. public event EventHandler<DataGridColumnEventArgs> ColumnReordered;
  116. /// <summary>
  117. /// Raised when starting a column reordering action. Subscribers to this event can
  118. /// set tooltip and caret UIElements, constrain tooltip position, indicate that
  119. /// a preview should be shown, or cancel reordering.
  120. /// </summary>
  121. public event EventHandler<DataGridColumnReorderingEventArgs> ColumnReordering;
  122. //
  123. public event EventHandler<EventArgs> CurrentCellChanged;
  124. public event EventHandler<DataGridPreparingCellForEditEventArgs> PreparingCellForEdit;
  125. public event EventHandler<DataGridRowEventArgs> LoadingRow;
  126. public event EventHandler<DataGridRowDetailsEventArgs> LoadingRowDetails;
  127. public event EventHandler<DataGridRowEventArgs> UnloadingRow;
  128. public event EventHandler<DataGridRowDetailsEventArgs> UnloadingRowDetails;
  129. public event EventHandler<DataGridRowDetailsEventArgs> RowDetailsVisibilityChanged;
  130. public event SelectionChangedEventHandler SelectionChanged;
  131. #endregion Events
  132. /// <summary>
  133. /// Initializes a new instance of the DataGrid class.
  134. /// </summary>
  135. [SuppressMessage("Microsoft.Performance", "CA1805:DoNotInitializeUnnecessarily", Justification="_minRowHeight should be 0.")]
  136. public DataGrid()
  137. {
  138. this.TabNavigation = KeyboardNavigationMode.Once;
  139. this.KeyDown += new KeyEventHandler(DataGrid_KeyDown);
  140. this.KeyUp += new KeyEventHandler(DataGrid_KeyUp);
  141. this.GotFocus += new RoutedEventHandler(DataGrid_GotFocus);
  142. this.LostFocus += new RoutedEventHandler(DataGrid_LostFocus);
  143. this._loadedRows = new List<DataGridRow>();
  144. this._editingBoundCells = new List<DataGridCell>(2);
  145. this._selectedItems = new DataGridSelectedItemsCollection(this);
  146. this.SetValueNoCallback(SelectedIndexProperty, -1);
  147. this.DisplayData = new DataGridDisplayData();
  148. this.ColumnsInternal = CreateColumnsInstance();
  149. this.SetValueNoCallback(ColumnWidthProperty, DataGridLength.Auto);
  150. this.SetValueNoCallback(MaxColumnWidthProperty, DATAGRID_defaultMaxColumnWidth);
  151. this.SetValueNoCallback(MinColumnWidthProperty, DATAGRID_defaultMinColumnWidth);
  152. this.SetValueNoCallback(RowHeightProperty, double.NaN);
  153. this.RowHeightEstimate = DATAGRID_defaultRowHeight;
  154. this.RowDetailsHeightEstimate = 0;
  155. this._rowHeaderDesiredWidth = 0;
  156. this.DataConnection = new DataGridDataConnection(this);
  157. //this._newRowLocation = DataGridNewRowLocation.Inline;
  158. this._showDetailsTable = new IndexToValueTable<Visibility>();
  159. this.AnchorRowIndex = -1;
  160. this._lastEstimatedRow = -1;
  161. this._editingColumnIndex = -1;
  162. this._mouseOverRowIndex = null;
  163. this.CurrentCellCoordinates = new DataGridCellCoordinates(-1, -1);
  164. this.SetValueNoCallback(RowHeaderWidthProperty, double.NaN);
  165. this.SetValueNoCallback(ColumnHeaderHeightProperty, double.NaN);
  166. this._addedSelectedItems = new List<object>();
  167. this._removedSelectedItems = new List<object>();
  168. DefaultStyleKey = typeof(DataGrid);
  169. }
  170. #region Dependency Properties
  171. #region AlternatingRowBackground
  172. /// <summary>
  173. /// Gets or sets a brush that describes the background of odd-numbered rows in the grid.
  174. /// </summary>
  175. public Brush AlternatingRowBackground
  176. {
  177. get { return GetValue(AlternatingRowBackgroundProperty) as Brush; }
  178. set { SetValue(AlternatingRowBackgroundProperty, value); }
  179. }
  180. /// <summary>
  181. /// Identifies the AlternatingRowBackground dependency property.
  182. /// </summary>
  183. public static readonly DependencyProperty AlternatingRowBackgroundProperty =
  184. DependencyProperty.Register(
  185. "AlternatingRowBackground",
  186. typeof(Brush),
  187. typeof(DataGrid),
  188. new PropertyMetadata(OnAlternatingRowBackgroundPropertyChanged));
  189. private static void OnAlternatingRowBackgroundPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  190. {
  191. DataGrid dataGrid = (DataGrid)d;
  192. if (dataGrid._rowsPresenter != null)
  193. {
  194. foreach (DataGridRow row in dataGrid._rowsPresenter.Children)
  195. {
  196. row.EnsureBackground();
  197. }
  198. }
  199. }
  200. #endregion AlternatingRowBackground
  201. #region AreRowDetailsFrozen
  202. /// <summary>
  203. /// Gets or sets a value indicating whether the horizontal ScrollBar of the DataGrid affects the
  204. /// details section of a row.
  205. /// </summary>
  206. public bool AreRowDetailsFrozen
  207. {
  208. get { return (bool)GetValue(AreRowDetailsFrozenProperty); }
  209. set { SetValue(AreRowDetailsFrozenProperty, value); }
  210. }
  211. /// <summary>
  212. /// Identifies the AreRowDetailsFrozen dependency property.
  213. /// </summary>
  214. public static readonly DependencyProperty AreRowDetailsFrozenProperty =
  215. DependencyProperty.Register(
  216. "AreRowDetailsFrozen",
  217. typeof(bool),
  218. typeof(DataGrid),
  219. null);
  220. #endregion AreRowDetailsFrozen
  221. #region AutoGenerateColumns
  222. /// <summary>
  223. /// Gets or sets a value indicating whether columns are created automatically when the ItemsSource
  224. /// property is set.
  225. /// </summary>
  226. public bool AutoGenerateColumns
  227. {
  228. get { return (bool)GetValue(AutoGenerateColumnsProperty); }
  229. set { SetValue(AutoGenerateColumnsProperty, value); }
  230. }
  231. /// <summary>
  232. /// Identifies the AutoGenerateColumns dependency property.
  233. /// </summary>
  234. public static readonly DependencyProperty AutoGenerateColumnsProperty =
  235. DependencyProperty.Register(
  236. "AutoGenerateColumns",
  237. typeof(bool),
  238. typeof(DataGrid),
  239. new PropertyMetadata(OnAutoGenerateColumnsPropertyChanged));
  240. private static void OnAutoGenerateColumnsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  241. {
  242. DataGrid dataGrid = (DataGrid)d;
  243. bool value = (bool)e.NewValue;
  244. if (value)
  245. {
  246. dataGrid.RefreshRowsAndColumns();
  247. }
  248. else
  249. {
  250. dataGrid.RemoveAutoGeneratedColumns();
  251. }
  252. }
  253. #endregion AutoGenerateColumns
  254. #region CanUserReorderColumns
  255. /// <summary>
  256. /// Gets or sets a value indicating whether users can reorder columns.
  257. /// </summary>
  258. public bool CanUserReorderColumns
  259. {
  260. get { return (bool)GetValue(CanUserReorderColumnsProperty); }
  261. set { SetValue(CanUserReorderColumnsProperty, value); }
  262. }
  263. /// <summary>
  264. /// Identifies the CanUserReorderColumns dependency property.
  265. /// </summary>
  266. public static readonly DependencyProperty CanUserReorderColumnsProperty =
  267. DependencyProperty.Register(
  268. "CanUserReorderColumns",
  269. typeof(bool),
  270. typeof(DataGrid),
  271. null);
  272. #endregion CanUserReorderColumns
  273. #region CanUserResizeColumns
  274. /// <summary>
  275. /// Gets or sets a value indicating whether users can resize columns.
  276. /// </summary>
  277. public bool CanUserResizeColumns
  278. {
  279. get { return (bool)GetValue(CanUserResizeColumnsProperty); }
  280. set { SetValue(CanUserResizeColumnsProperty, value); }
  281. }
  282. /// <summary>
  283. /// Identifies the CanUserResizeColumns dependency property.
  284. /// </summary>
  285. public static readonly DependencyProperty CanUserResizeColumnsProperty =
  286. DependencyProperty.Register(
  287. "CanUserResizeColumns",
  288. typeof(bool),
  289. typeof(DataGrid),
  290. null);
  291. #endregion CanUserResizeColumns
  292. #region CanUserSortColumns
  293. /// <summary>
  294. /// Gets or sets a value indicating whether users can sort columns.
  295. /// </summary>
  296. public bool CanUserSortColumns
  297. {
  298. get { return (bool)GetValue(CanUserSortColumnsProperty); }
  299. set { SetValue(CanUserSortColumnsProperty, value); }
  300. }
  301. /// <summary>
  302. /// Identifies the CanUserSortColumns dependency property.
  303. /// </summary>
  304. public static readonly DependencyProperty CanUserSortColumnsProperty =
  305. DependencyProperty.Register(
  306. "CanUserSortColumns",
  307. typeof(bool),
  308. typeof(DataGrid),
  309. null);
  310. #endregion CanUserSortColumns
  311. #region CellStyle
  312. /// <summary>
  313. /// Gets or sets the style used by cells when they are rendered.
  314. /// </summary>
  315. public Style CellStyle
  316. {
  317. get { return GetValue(CellStyleProperty) as Style; }
  318. set { SetValue(CellStyleProperty, value); }
  319. }
  320. public static readonly DependencyProperty CellStyleProperty =
  321. DependencyProperty.Register(
  322. "CellStyle",
  323. typeof(Style),
  324. typeof(DataGrid),
  325. new PropertyMetadata(OnCellStylePropertyChanged));
  326. private static void OnCellStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  327. {
  328. Style newStyle = e.NewValue as Style;
  329. if (newStyle != null)
  330. {
  331. DataGrid dataGrid = d as DataGrid;
  332. if (dataGrid != null && dataGrid._rowsPresenter != null)
  333. {
  334. foreach (DataGridRow row in dataGrid._rowsPresenter.Children)
  335. {
  336. foreach (DataGridCell cell in row.Cells)
  337. {
  338. cell.EnsureCellStyle();
  339. }
  340. }
  341. dataGrid.InvalidateRowHeightEstimate();
  342. }
  343. }
  344. }
  345. #endregion CellStyle
  346. #region ColumnHeaderHeight
  347. /// <summary>
  348. /// Gets or sets the suggested height of the grid's column headers.
  349. /// </summary>
  350. public double ColumnHeaderHeight
  351. {
  352. get { return (double)GetValue(ColumnHeaderHeightProperty); }
  353. set { SetValue(ColumnHeaderHeightProperty, value); }
  354. }
  355. /// <summary>
  356. /// Identifies the ColumnHeaderHeight dependency property.
  357. /// </summary>
  358. public static readonly DependencyProperty ColumnHeaderHeightProperty =
  359. DependencyProperty.Register(
  360. "ColumnHeaderHeight",
  361. typeof(double),
  362. typeof(DataGrid),
  363. new PropertyMetadata(OnColumnHeaderHeightPropertyChanged));
  364. /// <summary>
  365. /// ColumnHeaderHeightProperty property changed handler.
  366. /// </summary>
  367. /// <param name="d">DataGrid that changed its ColumnHeaderHeight.</param>
  368. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  369. private static void OnColumnHeaderHeightPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  370. {
  371. DataGrid dataGrid = (DataGrid)d;
  372. if (!dataGrid.IsHandlerSuspended(e.Property))
  373. {
  374. double value = (double)e.NewValue;
  375. if (value < DATAGRID_minimumColumnHeaderHeight)
  376. {
  377. dataGrid.SetValueNoCallback(e.Property, e.OldValue);
  378. throw DataGridError.DataGrid.ValueMustBeGreaterThanOrEqualTo("value", "ColumnHeaderHeight", DATAGRID_minimumColumnHeaderHeight);
  379. }
  380. if (value > DATAGRID_maxHeadersThickness)
  381. {
  382. dataGrid.SetValueNoCallback(e.Property, e.OldValue);
  383. throw DataGridError.DataGrid.ValueMustBeLessThanOrEqualTo("value", "ColumnHeaderHeight", DATAGRID_maxHeadersThickness);
  384. }
  385. dataGrid.InvalidateMeasure();
  386. }
  387. }
  388. #endregion ColumnHeaderHeight
  389. #region ColumnHeaderStyle
  390. /// <summary>
  391. /// Gets or sets the style used by column headers when they are rendered.
  392. /// </summary>
  393. public Style ColumnHeaderStyle
  394. {
  395. get { return GetValue(ColumnHeaderStyleProperty) as Style; }
  396. set { SetValue(ColumnHeaderStyleProperty, value); }
  397. }
  398. /// <summary>
  399. /// Identifies the ColumnHeaderStyle dependency property.
  400. /// </summary>
  401. public static readonly DependencyProperty ColumnHeaderStyleProperty = DependencyProperty.Register("ColumnHeaderStyle", typeof(Style), typeof(DataGrid), new PropertyMetadata(OnColumnHeaderStylePropertyChanged));
  402. private static void OnColumnHeaderStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  403. {
  404. //
  405. Style newStyle = e.NewValue as Style;
  406. if (newStyle != null)
  407. {
  408. DataGrid dataGrid = d as DataGrid;
  409. if (dataGrid != null)
  410. {
  411. Style oldStyle = e.OldValue as Style;
  412. foreach (DataGridColumn column in dataGrid.Columns)
  413. {
  414. EnsureColumnHeaderCellStyle(column, oldStyle, newStyle);
  415. }
  416. EnsureColumnHeaderCellStyle(dataGrid.ColumnsInternal.FillerColumn, oldStyle, newStyle);
  417. }
  418. }
  419. }
  420. #endregion ColumnHeaderStyle
  421. #region ColumnWidth
  422. /// <summary>
  423. /// Gets or sets the width of the grid's columns.
  424. /// </summary>
  425. public DataGridLength ColumnWidth
  426. {
  427. get { return (DataGridLength)GetValue(ColumnWidthProperty); }
  428. set { SetValue(ColumnWidthProperty, value); }
  429. }
  430. /// <summary>
  431. /// Identifies the ColumnWidth dependency property.
  432. /// </summary>
  433. public static readonly DependencyProperty ColumnWidthProperty =
  434. DependencyProperty.Register(
  435. "ColumnWidth",
  436. typeof(DataGridLength),
  437. typeof(DataGrid),
  438. new PropertyMetadata(OnColumnWidthPropertyChanged));
  439. /// <summary>
  440. /// ColumnWidthProperty property changed handler.
  441. /// </summary>
  442. /// <param name="d">DataGrid that changed its ColumnWidth.</param>
  443. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  444. private static void OnColumnWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  445. {
  446. DataGrid dataGrid = (DataGrid)d;
  447. dataGrid.EnsureHorizontalLayout();
  448. }
  449. #endregion ColumnWidth
  450. #region DragIndicatorStyle
  451. /// <summary>
  452. /// Gets or sets the style used by rows when they are rendered.
  453. /// </summary>
  454. public Style DragIndicatorStyle
  455. {
  456. get { return GetValue(DragIndicatorStyleProperty) as Style; }
  457. set { SetValue(DragIndicatorStyleProperty, value); }
  458. }
  459. public static readonly DependencyProperty DragIndicatorStyleProperty =
  460. DependencyProperty.Register(
  461. "DragIndicatorStyle",
  462. typeof(Style),
  463. typeof(DataGrid),
  464. null);
  465. #endregion DragIndicatorStyle
  466. #region DropLocationIndicatorStyle
  467. /// <summary>
  468. /// Gets or sets the style used by rows when they are rendered.
  469. /// </summary>
  470. public Style DropLocationIndicatorStyle
  471. {
  472. get { return GetValue(DropLocationIndicatorStyleProperty) as Style; }
  473. set { SetValue(DropLocationIndicatorStyleProperty, value); }
  474. }
  475. public static readonly DependencyProperty DropLocationIndicatorStyleProperty =
  476. DependencyProperty.Register(
  477. "DropLocationIndicatorStyle",
  478. typeof(Style),
  479. typeof(DataGrid),
  480. null);
  481. #endregion DropLocationIndicatorStyle
  482. #region FrozenColumnCount
  483. public int FrozenColumnCount
  484. {
  485. get { return (int)GetValue(FrozenColumnCountProperty); }
  486. set { SetValue(FrozenColumnCountProperty, value); }
  487. }
  488. public static readonly DependencyProperty FrozenColumnCountProperty =
  489. DependencyProperty.Register(
  490. "FrozenColumnCount",
  491. typeof(int),
  492. typeof(DataGrid),
  493. new PropertyMetadata(OnFrozenColumnCountPropertyChanged));
  494. private static void OnFrozenColumnCountPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  495. {
  496. ProcessFrozenColumnCount((DataGrid)d);
  497. }
  498. private static void ProcessFrozenColumnCount(DataGrid dataGrid)
  499. {
  500. dataGrid.CorrectColumnFrozenStates();
  501. dataGrid.ComputeScrollBarsLayout();
  502. dataGrid.InvalidateColumnHeadersArrange();
  503. dataGrid.InvalidateCellsArrange();
  504. }
  505. #endregion FrozenColumnCount
  506. #region GridLinesVisibility
  507. /// <summary>
  508. /// Gets or sets a value that indicates whether horizontal or vertical gridlines for
  509. /// the inner cells should be displayed.
  510. /// </summary>
  511. public DataGridGridLinesVisibility GridLinesVisibility
  512. {
  513. get { return (DataGridGridLinesVisibility)GetValue(GridLinesVisibilityProperty); }
  514. set { SetValue(GridLinesVisibilityProperty, value); }
  515. }
  516. /// <summary>
  517. /// Identifies the GridLines dependency property.
  518. /// </summary>
  519. public static readonly DependencyProperty GridLinesVisibilityProperty =
  520. DependencyProperty.Register(
  521. "GridLinesVisibility",
  522. typeof(DataGridGridLinesVisibility),
  523. typeof(DataGrid),
  524. new PropertyMetadata(OnGridLinesVisibilityPropertyChanged));
  525. /// <summary>
  526. /// GridLinesProperty property changed handler.
  527. /// </summary>
  528. /// <param name="d">DataGrid that changed its GridLines.</param>
  529. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  530. private static void OnGridLinesVisibilityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  531. {
  532. DataGrid dataGrid = (DataGrid)d;
  533. if (!dataGrid.IsHandlerSuspended(e.Property) && dataGrid._rowsPresenter != null)
  534. {
  535. foreach (DataGridRow row in dataGrid._rowsPresenter.Children)
  536. {
  537. row.EnsureGridLines();
  538. row.InvalidateHorizontalArrange();
  539. }
  540. }
  541. }
  542. #endregion GridLinesVisibility
  543. #region HeadersVisibility
  544. /// <summary>
  545. /// Gets or sets a value that indicates whether column or row headers should be displayed.
  546. /// </summary>
  547. public DataGridHeadersVisibility HeadersVisibility
  548. {
  549. get { return (DataGridHeadersVisibility)GetValue(HeadersVisibilityProperty); }
  550. set { SetValue(HeadersVisibilityProperty, value); }
  551. }
  552. /// <summary>
  553. /// Identifies the HeadersVisibility dependency property.
  554. /// </summary>
  555. public static readonly DependencyProperty HeadersVisibilityProperty =
  556. DependencyProperty.Register(
  557. "HeadersVisibility",
  558. typeof(DataGridHeadersVisibility),
  559. typeof(DataGrid),
  560. new PropertyMetadata(OnHeadersVisibilityPropertyChanged));
  561. /// <summary>
  562. /// HeadersVisibilityProperty property changed handler.
  563. /// </summary>
  564. /// <param name="d">DataGrid that changed its HeadersVisibility.</param>
  565. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  566. private static void OnHeadersVisibilityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  567. {
  568. DataGrid dataGrid = (DataGrid)d;
  569. if (!dataGrid.IsHandlerSuspended(e.Property))
  570. {
  571. DataGridHeadersVisibility newValue = (DataGridHeadersVisibility)e.NewValue;
  572. DataGridHeadersVisibility oldValue = (DataGridHeadersVisibility)e.OldValue;
  573. Func<DataGridHeadersVisibility, DataGridHeadersVisibility, bool> hasFlags = (DataGridHeadersVisibility value, DataGridHeadersVisibility flags) => ((value & flags) == flags);
  574. bool newValueCols = hasFlags(newValue, DataGridHeadersVisibility.Column);
  575. bool newValueRows = hasFlags(newValue, DataGridHeadersVisibility.Row);
  576. bool oldValueCols = hasFlags(oldValue, DataGridHeadersVisibility.Column);
  577. bool oldValueRows = hasFlags(oldValue, DataGridHeadersVisibility.Row);
  578. // Columns
  579. if (newValueCols != oldValueCols)
  580. {
  581. if (dataGrid._columnHeadersPresenter != null)
  582. {
  583. dataGrid.EnsureColumnHeadersVisibility();
  584. if (!newValueCols)
  585. {
  586. dataGrid._columnHeadersPresenter.Measure(Size.Empty);
  587. }
  588. dataGrid.InvalidateMeasure();
  589. }
  590. }
  591. // Rows
  592. if (newValueRows != oldValueRows)
  593. {
  594. if (dataGrid._rowsPresenter != null)
  595. {
  596. foreach (DataGridRow row in dataGrid._rowsPresenter.Children)
  597. {
  598. row.EnsureHeaderStyleAndVisibility();
  599. if (newValueRows)
  600. {
  601. row.ApplyState(false /*animate*/);
  602. row.EnsureHeaderVisibility();
  603. }
  604. }
  605. dataGrid.InvalidateRowHeightEstimate();
  606. dataGrid.InvalidateRowsMeasure(true /*invalidateIndividualRows*/);
  607. }
  608. }
  609. //
  610. if (dataGrid._topLeftCornerHeader != null)
  611. {
  612. dataGrid._topLeftCornerHeader.Visibility = newValueRows && newValueCols ? Visibility.Visible : Visibility.Collapsed;
  613. if (dataGrid._topLeftCornerHeader.Visibility == Visibility.Collapsed)
  614. {
  615. dataGrid._topLeftCornerHeader.Measure(Size.Empty);
  616. }
  617. }
  618. }
  619. }
  620. #endregion HeadersVisibility
  621. #region HorizontalGridLinesBrush
  622. /// <summary>
  623. /// Gets or sets a brush that describes the horizontal gridlines color.
  624. /// </summary>
  625. public Brush HorizontalGridLinesBrush
  626. {
  627. get { return GetValue(HorizontalGridLinesBrushProperty) as Brush; }
  628. set { SetValue(HorizontalGridLinesBrushProperty, value); }
  629. }
  630. /// <summary>
  631. /// Identifies the HorizontalGridLinesBrush dependency property.
  632. /// </summary>
  633. public static readonly DependencyProperty HorizontalGridLinesBrushProperty =
  634. DependencyProperty.Register(
  635. "HorizontalGridLinesBrush",
  636. typeof(Brush),
  637. typeof(DataGrid),
  638. new PropertyMetadata(OnHorizontalGridLinesBrushPropertyChanged));
  639. /// <summary>
  640. /// HorizontalGridLinesBrushProperty property changed handler.
  641. /// </summary>
  642. /// <param name="d">DataGrid that changed its HorizontalGridLinesBrush.</param>
  643. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  644. private static void OnHorizontalGridLinesBrushPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  645. {
  646. DataGrid dataGrid = (DataGrid)d;
  647. if (!dataGrid.IsHandlerSuspended(e.Property) && dataGrid._rowsPresenter != null)
  648. {
  649. foreach (DataGridRow row in dataGrid._rowsPresenter.Children)
  650. {
  651. row.EnsureGridLines();
  652. }
  653. }
  654. }
  655. #endregion HorizontalGridLinesBrush
  656. #region HorizontalScrollBarVisibility
  657. /// <summary>
  658. /// Gets or sets a value that indicates whether a horizontal ScrollBar should be displayed.
  659. /// </summary>
  660. public ScrollBarVisibility HorizontalScrollBarVisibility
  661. {
  662. get { return (ScrollBarVisibility)GetValue(HorizontalScrollBarVisibilityProperty); }
  663. set { SetValue(HorizontalScrollBarVisibilityProperty, value); }
  664. }
  665. /// <summary>
  666. /// Identifies the HorizontalScrollBarVisibility dependency property.
  667. /// </summary>
  668. public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty =
  669. DependencyProperty.Register(
  670. "HorizontalScrollBarVisibility",
  671. typeof(ScrollBarVisibility),
  672. typeof(DataGrid),
  673. new PropertyMetadata(OnHorizontalScrollBarVisibilityPropertyChanged));
  674. /// <summary>
  675. /// HorizontalScrollBarVisibilityProperty property changed handler.
  676. /// </summary>
  677. /// <param name="d">DataGrid that changed its HorizontalScrollBarVisibility.</param>
  678. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  679. private static void OnHorizontalScrollBarVisibilityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  680. {
  681. DataGrid dataGrid = (DataGrid)d;
  682. if (!dataGrid.IsHandlerSuspended(e.Property) &&
  683. (ScrollBarVisibility)e.NewValue != (ScrollBarVisibility)e.OldValue &&
  684. dataGrid._hScrollBar != null)
  685. {
  686. dataGrid.InvalidateMeasure();
  687. }
  688. }
  689. #endregion HorizontalScrollBarVisibility
  690. #region IsReadOnly
  691. /// <summary>
  692. /// Gets or sets a value indicating whether the user can edit the cells of the DataGrid control.
  693. /// </summary>
  694. public bool IsReadOnly
  695. {
  696. get { return (bool)GetValue(IsReadOnlyProperty); }
  697. set { SetValue(IsReadOnlyProperty, value); }
  698. }
  699. /// <summary>
  700. /// Identifies the IsReadOnly dependency property.
  701. /// </summary>
  702. public static readonly DependencyProperty IsReadOnlyProperty =
  703. DependencyProperty.Register(
  704. "IsReadOnly",
  705. typeof(bool),
  706. typeof(DataGrid),
  707. new PropertyMetadata(OnIsReadOnlyPropertyChanged));
  708. /// <summary>
  709. /// IsReadOnlyProperty property changed handler.
  710. /// </summary>
  711. /// <param name="d">DataGrid that changed its IsReadOnly.</param>
  712. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  713. private static void OnIsReadOnlyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  714. {
  715. DataGrid dataGrid = (DataGrid)d;
  716. if (!dataGrid.IsHandlerSuspended(e.Property))
  717. {
  718. bool value = (bool)e.NewValue;
  719. if (value && !dataGrid.CommitEdit(DataGridEditingUnit.Row, true /*exitEditing*/))
  720. {
  721. d.SetValueNoCallback(e.Property, e.OldValue);
  722. throw DataGridError.DataGrid.CommitFailedCannotCompleteOperation();
  723. }
  724. }
  725. }
  726. #endregion IsReadOnly
  727. #region ItemsSource
  728. /// <summary>
  729. /// Gets or sets a collection used to generate the content of the DataGrid.
  730. /// </summary>
  731. public IEnumerable ItemsSource
  732. {
  733. get { return GetValue(ItemsSourceProperty) as IEnumerable; }
  734. set { SetValue(ItemsSourceProperty, value); }
  735. }
  736. /// <summary>
  737. /// Identifies the ItemsSource dependency property.
  738. /// </summary>
  739. public static readonly DependencyProperty ItemsSourceProperty =
  740. DependencyProperty.Register(
  741. "ItemsSource",
  742. typeof(IEnumerable),
  743. typeof(DataGrid),
  744. new PropertyMetadata(OnItemsSourcePropertyChanged));
  745. /// <summary>
  746. /// ItemsSourceProperty property changed handler.
  747. /// </summary>
  748. /// <param name="d">DataGrid that changed its ItemsSource.</param>
  749. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  750. private static void OnItemsSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  751. {
  752. DataGrid dataGrid = (DataGrid)d;
  753. if (!dataGrid.IsHandlerSuspended(e.Property))
  754. {
  755. Debug.Assert(dataGrid.DataConnection != null);
  756. if (dataGrid.LoadingOrUnloadingRow)
  757. {
  758. dataGrid.SetValueNoCallback(ItemsSourceProperty, e.OldValue);
  759. throw DataGridError.DataGrid.CannotChangeItemsWhenLoadingRows();
  760. }
  761. dataGrid.DataConnection.UnWireEvents(dataGrid.DataConnection.DataSource);
  762. dataGrid.DataConnection.ClearDataProperties();
  763. // Wrap an IList in a CollectionView if it's not already one
  764. IEnumerable newDataSource;
  765. IList tempList = e.NewValue as IList;
  766. if (tempList != null && !(e.NewValue is System.ComponentModel.ICollectionView))
  767. {
  768. newDataSource = new ListCollectionView(tempList);
  769. }
  770. else
  771. {
  772. newDataSource = (IEnumerable)e.NewValue;
  773. }
  774. dataGrid.DataConnection.DataSource = newDataSource;
  775. if (newDataSource != null)
  776. {
  777. dataGrid.DataConnection.WireEvents(newDataSource);
  778. }
  779. // we always want to do this
  780. dataGrid.RefreshRowsAndColumns();
  781. }
  782. }
  783. #endregion ItemsSource
  784. #region MaxColumnWidth
  785. /// <summary>
  786. /// Gets or sets the width of the grid's columns.
  787. /// </summary>
  788. public double MaxColumnWidth
  789. {
  790. get { return (double)GetValue(MaxColumnWidthProperty); }
  791. set { SetValue(MaxColumnWidthProperty, value); }
  792. }
  793. /// <summary>
  794. /// Identifies the MaxColumnWidth dependency property.
  795. /// </summary>
  796. public static readonly DependencyProperty MaxColumnWidthProperty =
  797. DependencyProperty.Register(
  798. "MaxColumnWidth",
  799. typeof(double),
  800. typeof(DataGrid),
  801. new PropertyMetadata(OnMaxColumnWidthPropertyChanged));
  802. /// <summary>
  803. /// MaxColumnWidthProperty property changed handler.
  804. /// </summary>
  805. /// <param name="d">DataGrid that changed its ColumnWidth.</param>
  806. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  807. private static void OnMaxColumnWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  808. {
  809. DataGrid dataGrid = (DataGrid)d;
  810. double newValue = (double)e.NewValue;
  811. if (double.IsNaN(newValue))
  812. {
  813. dataGrid.SetValueNoCallback(e.Property, e.OldValue);
  814. throw DataGridError.DataGrid.ValueCannotBeSetToNAN("MaxColumnWidth");
  815. }
  816. if (newValue < 0)
  817. {
  818. dataGrid.SetValueNoCallback(e.Property, e.OldValue);
  819. throw DataGridError.DataGrid.ValueMustBeGreaterThanOrEqualTo("value", "MaxColumnWidth", 0);
  820. }
  821. if (dataGrid.MinColumnWidth > newValue)
  822. {
  823. dataGrid.SetValueNoCallback(e.Property, e.OldValue);
  824. throw DataGridError.DataGrid.ValueMustBeGreaterThanOrEqualTo("value", "MaxColumnWidth", "MinColumnWidth");
  825. }
  826. dataGrid.ColumnsInternal.EnsureVisibleEdgedColumnsWidth();
  827. dataGrid.InvalidateColumnHeadersMeasure();
  828. dataGrid.InvalidateRowsMeasure(true);
  829. }
  830. #endregion MaxColumnWidth
  831. #region MinColumnWidth
  832. /// <summary>
  833. /// Gets or sets the width of the grid's columns.
  834. /// </summary>
  835. public double MinColumnWidth
  836. {
  837. get { return (double)GetValue(MinColumnWidthProperty); }
  838. set { SetValue(MinColumnWidthProperty, value); }
  839. }
  840. /// <summary>
  841. /// Identifies the MinColumnWidth dependency property.
  842. /// </summary>
  843. public static readonly DependencyProperty MinColumnWidthProperty =
  844. DependencyProperty.Register(
  845. "MinColumnWidth",
  846. typeof(double),
  847. typeof(DataGrid),
  848. new PropertyMetadata(OnMinColumnWidthPropertyChanged));
  849. /// <summary>
  850. /// MinColumnWidthProperty property changed handler.
  851. /// </summary>
  852. /// <param name="d">DataGrid that changed its ColumnWidth.</param>
  853. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  854. private static void OnMinColumnWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  855. {
  856. DataGrid dataGrid = (DataGrid)d;
  857. double newValue = (double)e.NewValue;
  858. if (double.IsNaN(newValue))
  859. {
  860. dataGrid.SetValueNoCallback(e.Property, e.OldValue);
  861. throw DataGridError.DataGrid.ValueCannotBeSetToNAN("MinColumnWidth");
  862. }
  863. if (newValue < 0)
  864. {
  865. dataGrid.SetValueNoCallback(e.Property, e.OldValue);
  866. throw DataGridError.DataGrid.ValueMustBeGreaterThanOrEqualTo("value", "MinColumnWidth", 0);
  867. }
  868. if (double.IsPositiveInfinity(newValue))
  869. {
  870. dataGrid.SetValueNoCallback(e.Property, e.OldValue);
  871. throw DataGridError.DataGrid.ValueCannotBeSetToInfinity("MinColumnWidth");
  872. }
  873. if (dataGrid.MaxColumnWidth < newValue)
  874. {
  875. dataGrid.SetValueNoCallback(e.Property, e.OldValue);
  876. throw DataGridError.DataGrid.ValueMustBeLessThanOrEqualTo("value", "MinColumnWidth", "MaxColumnWidth");
  877. }
  878. dataGrid.ColumnsInternal.EnsureVisibleEdgedColumnsWidth();
  879. dataGrid.InvalidateColumnHeadersMeasure();
  880. dataGrid.InvalidateRowsMeasure(true);
  881. }
  882. #endregion MinColumnWidth
  883. #region RowBackground
  884. /// <summary>
  885. /// Gets or sets a brush that describes the background of a row in the grid.
  886. /// </summary>
  887. public Brush RowBackground
  888. {
  889. get { return GetValue(RowBackgroundProperty) as Brush; }
  890. set { SetValue(RowBackgroundProperty, value); }
  891. }
  892. public static readonly DependencyProperty RowBackgroundProperty = DependencyProperty.Register("RowBackground", typeof(Brush), typeof(DataGrid), new PropertyMetadata(OnRowBackgroundPropertyChanged));
  893. private static void OnRowBackgroundPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  894. {
  895. DataGrid dataGrid = (DataGrid)d;
  896. if (dataGrid._rowsPresenter != null)
  897. {
  898. // Go through the Displayed rows and update the background
  899. foreach (DataGridRow row in dataGrid._rowsPresenter.Children)
  900. {
  901. row.EnsureBackground();
  902. }
  903. }
  904. }
  905. #endregion RowBackground
  906. #region RowDetailsTemplate
  907. /// <summary>
  908. /// Gets or sets the DataTemplate used to display the details section of a row.
  909. /// </summary>
  910. public DataTemplate RowDetailsTemplate
  911. {
  912. get { return GetValue(RowDetailsTemplateProperty) as DataTemplate; }
  913. set { SetValue(RowDetailsTemplateProperty, value); }
  914. }
  915. /// <summary>
  916. /// Identifies the RowDetailsTemplate dependency property.
  917. /// </summary>
  918. public static readonly DependencyProperty RowDetailsTemplateProperty =
  919. DependencyProperty.Register(
  920. "RowDetailsTemplate",
  921. typeof(DataTemplate),
  922. typeof(DataGrid),
  923. new PropertyMetadata(OnRowDetailsTemplatePropertyChanged));
  924. private static void OnRowDetailsTemplatePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  925. {
  926. DataGrid dataGrid = (DataGrid)d;
  927. // Update the RowDetails templates if necessary
  928. if (dataGrid._rowsPresenter != null)
  929. {
  930. foreach (DataGridRow row in dataGrid._rowsPresenter.Children)
  931. {
  932. if (dataGrid.GetRowDetailsVisibility(row.Index) == Visibility.Visible)
  933. {
  934. // DetailsPreferredHeight is initialized when the DetailsElement's size changes.
  935. row.ApplyDetailsTemplate(false /*initializeDetailsPreferredHeight*/);
  936. }
  937. }
  938. }
  939. dataGrid.UpdateRowDetailsHeightEstimate();
  940. dataGrid.InvalidateMeasure();
  941. }
  942. #endregion RowDetailsTemplate
  943. #region RowDetailsVisibilityMode
  944. /// <summary>
  945. /// Gets or sets a value that indicates when the details section of a row should be displayed.
  946. /// </summary>
  947. //
  948. [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")]
  949. public DataGridRowDetailsVisibilityMode RowDetailsVisibilityMode
  950. {
  951. get { return (DataGridRowDetailsVisibilityMode)GetValue(RowDetailsVisibilityModeProperty); }
  952. set { SetValue(RowDetailsVisibilityModeProperty, value); }
  953. }
  954. /// <summary>
  955. /// Identifies the RowDetailsVisibilityMode dependency property.
  956. /// </summary>
  957. public static readonly DependencyProperty RowDetailsVisibilityModeProperty =
  958. DependencyProperty.Register(
  959. "RowDetailsVisibilityMode",
  960. typeof(DataGridRowDetailsVisibilityMode),
  961. typeof(DataGrid),
  962. new PropertyMetadata(OnRowDetailsVisibilityModePropertyChanged));
  963. /// <summary>
  964. /// RowDetailsVisibilityModeProperty property changed handler.
  965. /// </summary>
  966. /// <param name="d">DataGrid that changed its RowDetailsVisibilityMode.</param>
  967. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  968. private static void OnRowDetailsVisibilityModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  969. {
  970. DataGrid dataGrid = (DataGrid)d;
  971. if (dataGrid._rowsPresenter != null && dataGrid.RowCount > 0)
  972. {
  973. DataGridRowDetailsVisibilityMode newDetailsMode = (DataGridRowDetailsVisibilityMode)e.NewValue;
  974. Visibility newDetailsVisibility = Visibility.Collapsed;
  975. switch (newDetailsMode)
  976. {
  977. case DataGridRowDetailsVisibilityMode.Visible:
  978. newDetailsVisibility = Visibility.Visible;
  979. dataGrid._showDetailsTable.AddValues(0, dataGrid.RowCount, Visibility.Visible);
  980. break;
  981. case DataGridRowDetailsVisibilityMode.Collapsed:
  982. newDetailsVisibility = Visibility.Collapsed;
  983. dataGrid._showDetailsTable.AddValues(0, dataGrid.RowCount, Visibility.Collapsed);
  984. break;
  985. case DataGridRowDetailsVisibilityMode.VisibleWhenSelected:
  986. dataGrid._showDetailsTable.Clear();
  987. break;
  988. }
  989. bool updated = false;
  990. foreach (DataGridRow row in dataGrid._rowsPresenter.Children)
  991. {
  992. Debug.Assert(row.Index != -1);
  993. if (newDetailsMode == DataGridRowDetailsVisibilityMode.VisibleWhenSelected)
  994. {
  995. // For VisibleWhenSelected, we need to calculate the value for each individual row
  996. newDetailsVisibility = dataGrid._selectedItems.Contains(row.Index) ? Visibility.Visible : Visibility.Collapsed;
  997. }
  998. if (row.DetailsVisibility != newDetailsVisibility)
  999. {
  1000. updated = true;
  1001. row.SetDetailsVisibilityInternal(newDetailsVisibility, true /* raiseNotification */, false /* animate */);
  1002. }
  1003. }
  1004. if (updated)
  1005. {
  1006. dataGrid.UpdateDisplayedRows(dataGrid.DisplayData.FirstDisplayedScrollingRow, dataGrid.CellsHeight);
  1007. dataGrid.InvalidateRowsMeasure(false /*invalidateIndividualRows*/);
  1008. }
  1009. }
  1010. }
  1011. #endregion RowDetailsVisibilityMode
  1012. #region RowHeight
  1013. /// <summary>
  1014. /// Gets or sets the suggested height of the grid's rows.
  1015. /// </summary>
  1016. public double RowHeight
  1017. {
  1018. get { return (double)GetValue(RowHeightProperty); }
  1019. set { SetValue(RowHeightProperty, value); }
  1020. }
  1021. /// <summary>
  1022. /// Identifies the RowHeight dependency property.
  1023. /// </summary>
  1024. public static readonly DependencyProperty RowHeightProperty =
  1025. DependencyProperty.Register(
  1026. "RowHeight",
  1027. typeof(double),
  1028. typeof(DataGrid),
  1029. new PropertyMetadata(OnRowHeightPropertyChanged));
  1030. /// <summary>
  1031. /// RowHeightProperty property changed handler.
  1032. /// </summary>
  1033. /// <param name="d">DataGrid that changed its RowHeight.</param>
  1034. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  1035. [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly", Justification = "This parameter is exposed to the user as a 'RowHeight' dependency property.")]
  1036. private static void OnRowHeightPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  1037. {
  1038. DataGrid dataGrid = (DataGrid)d;
  1039. if (!dataGrid.IsHandlerSuspended(e.Property))
  1040. {
  1041. double value = (double)e.NewValue;
  1042. if (value < DataGridRow.DATAGRIDROW_minimumHeight)
  1043. {
  1044. dataGrid.SetValueNoCallback(e.Property, e.OldValue);
  1045. throw DataGridError.DataGrid.ValueMustBeGreaterThanOrEqualTo("value", "RowHeight", 0);
  1046. }
  1047. if (value > DataGridRow.DATAGRIDROW_maximumHeight)
  1048. {
  1049. dataGrid.SetValueNoCallback(e.Property, e.OldValue);
  1050. throw DataGridError.DataGrid.ValueMustBeLessThanOrEqualTo("value", "RowHeight", DataGridRow.DATAGRIDROW_maximumHeight);
  1051. }
  1052. dataGrid.InvalidateRowHeightEstimate();
  1053. // Re-measure all the rows due to the Height change
  1054. dataGrid.InvalidateRowsMeasure(true);
  1055. // DataGrid needs to update the layout information and the ScrollBars
  1056. dataGrid.InvalidateMeasure();
  1057. }
  1058. }
  1059. #endregion RowHeight
  1060. #region RowHeaderWidth
  1061. /// <summary>
  1062. /// Gets or sets the width of the grid's row headers.
  1063. /// </summary>
  1064. public double RowHeaderWidth
  1065. {
  1066. get { return (double)GetValue(RowHeaderWidthProperty); }
  1067. set { SetValue(RowHeaderWidthProperty, value); }
  1068. }
  1069. /// <summary>
  1070. /// Identifies the RowHeaderWidth dependency property.
  1071. /// </summary>
  1072. public static readonly DependencyProperty RowHeaderWidthProperty =
  1073. DependencyProperty.Register(
  1074. "RowHeaderWidth",
  1075. typeof(double),
  1076. typeof(DataGrid),
  1077. new PropertyMetadata(OnRowHeaderWidthPropertyChanged));
  1078. /// <summary>
  1079. /// RowHeaderWidthProperty property changed handler.
  1080. /// </summary>
  1081. /// <param name="d">DataGrid that changed its RowHeaderWidth.</param>
  1082. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  1083. private static void OnRowHeaderWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  1084. {
  1085. DataGrid dataGrid = (DataGrid)d;
  1086. if (!dataGrid.IsHandlerSuspended(e.Property))
  1087. {
  1088. double value = (double)e.NewValue;
  1089. if (value < DATAGRID_minimumRowHeaderWidth)
  1090. {
  1091. dataGrid.SetValueNoCallback(e.Property, e.OldValue);
  1092. throw DataGridError.DataGrid.ValueMustBeGreaterThanOrEqualTo("value", "RowHeaderWidth", DATAGRID_minimumRowHeaderWidth);
  1093. }
  1094. if (value > DATAGRID_maxHeadersThickness)
  1095. {
  1096. dataGrid.SetValueNoCallback(e.Property, e.OldValue);
  1097. throw DataGridError.DataGrid.ValueMustBeLessThanOrEqualTo("value", "RowHeaderWidth", DATAGRID_maxHeadersThickness);
  1098. }
  1099. dataGrid.EnsureRowHeaderWidth();
  1100. }
  1101. }
  1102. #endregion RowHeaderWidth
  1103. #region RowHeaderStyle
  1104. /// <summary>
  1105. /// Gets or sets the style used by row headers when they are rendered.
  1106. /// </summary>
  1107. public Style RowHeaderStyle
  1108. {
  1109. get { return GetValue(RowHeaderStyleProperty) as Style; }
  1110. set { SetValue(RowHeaderStyleProperty, value); }
  1111. }
  1112. public static readonly DependencyProperty RowHeaderStyleProperty = DependencyProperty.Register("RowHeaderStyle", typeof(Style), typeof(DataGrid), new PropertyMetadata(OnRowHeaderStylePropertyChanged));
  1113. private static void OnRowHeaderStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  1114. {
  1115. Style newStyle = e.NewValue as Style;
  1116. if (newStyle != null)
  1117. {
  1118. DataGrid dataGrid = d as DataGrid;
  1119. if (dataGrid != null && dataGrid._rowsPresenter != null)
  1120. {
  1121. // Set HeaderCell.Style for displayed rows if HeaderCell.Style is not already set
  1122. foreach (DataGridRow row in dataGrid._rowsPresenter.Children)
  1123. {
  1124. row.EnsureHeaderStyleAndVisibility();
  1125. }
  1126. dataGrid.InvalidateRowHeightEstimate();
  1127. }
  1128. }
  1129. }
  1130. #endregion RowHeaderStyle
  1131. #region RowStyle
  1132. /// <summary>
  1133. /// Gets or sets the style used by rows when they are rendered.
  1134. /// </summary>
  1135. public Style RowStyle
  1136. {
  1137. get { return GetValue(RowStyleProperty) as Style; }
  1138. set { SetValue(RowStyleProperty, value); }
  1139. }
  1140. public static readonly DependencyProperty RowStyleProperty =
  1141. DependencyProperty.Register(
  1142. "RowStyle",
  1143. typeof(Style),
  1144. typeof(DataGrid),
  1145. new PropertyMetadata(OnRowStylePropertyChanged));
  1146. private static void OnRowStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  1147. {
  1148. Style newStyle = e.NewValue as Style;
  1149. if (newStyle != null)
  1150. {
  1151. DataGrid dataGrid = d as DataGrid;
  1152. if (dataGrid != null)
  1153. {
  1154. Style oldStyle = e.OldValue as Style;
  1155. if (dataGrid._rowsPresenter != null)
  1156. {
  1157. // Set the style for displayed rows if it has not already been set
  1158. foreach (DataGridRow row in dataGrid._rowsPresenter.Children)
  1159. {
  1160. EnsureRowStyle(row, oldStyle, newStyle);
  1161. }
  1162. }
  1163. dataGrid.InvalidateRowHeightEstimate();
  1164. }
  1165. }
  1166. }
  1167. #endregion RowStyle
  1168. #region SelectionMode
  1169. /// <summary>
  1170. /// Gets or sets the selection behavior for a DataGrid.
  1171. /// </summary>
  1172. public DataGridSelectionMode SelectionMode
  1173. {
  1174. get { return (DataGridSelectionMode)GetValue(SelectionModeProperty); }
  1175. set { SetValue(SelectionModeProperty, value); }
  1176. }
  1177. /// <summary>
  1178. /// Identifies the SelectionMode dependency property.
  1179. /// </summary>
  1180. public static readonly DependencyProperty SelectionModeProperty =
  1181. DependencyProperty.Register(
  1182. "SelectionMode",
  1183. typeof(DataGridSelectionMode),
  1184. typeof(DataGrid),
  1185. new PropertyMetadata(OnSelectionModePropertyChanged));
  1186. /// <summary>
  1187. /// SelectionModeProperty property changed handler.
  1188. /// </summary>
  1189. /// <param name="d">DataGrid that changed its SelectionMode.</param>
  1190. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  1191. private static void OnSelectionModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  1192. {
  1193. DataGrid dataGrid = (DataGrid)d;
  1194. if (!dataGrid.IsHandlerSuspended(e.Property))
  1195. {
  1196. dataGrid.ClearRowSelection(true /*resetAnchorRowIndex*/);
  1197. }
  1198. }
  1199. #endregion SelectionMode
  1200. #region SelectedIndex
  1201. /// <summary>
  1202. /// Gets or sets the index of the current selection or returns -1 if the selection is empty.
  1203. /// </summary>
  1204. public int SelectedIndex
  1205. {
  1206. get { return (int)GetValue(SelectedIndexProperty); }
  1207. set { SetValue(SelectedIndexProperty, value); }
  1208. }
  1209. /// <summary>
  1210. /// Identifies the SelectedIndex dependency property.
  1211. /// </summary>
  1212. public static readonly DependencyProperty SelectedIndexProperty =
  1213. DependencyProperty.Register(
  1214. "SelectedIndex",
  1215. typeof(int),
  1216. typeof(DataGrid),
  1217. new PropertyMetadata(OnSelectedIndexPropertyChanged));
  1218. /// <summary>
  1219. /// SelectedIndexProperty property changed handler.
  1220. /// </summary>
  1221. /// <param name="d">DataGrid that changed its SelectedIndex.</param>
  1222. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  1223. private static void OnSelectedIndexPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  1224. {
  1225. DataGrid dataGrid = (DataGrid)d;
  1226. if (!dataGrid.IsHandlerSuspended(e.Property))
  1227. {
  1228. int index = (int)e.NewValue;
  1229. // GetDataItem returns null if index is >= Count, we do not check newValue
  1230. // against Count here to avoid enumerating through an Enumerable twice
  1231. // Setting SelectedItem coerces the finally value of the SelectedIndex
  1232. dataGrid.SelectedItem = (index < 0) ? null : dataGrid.DataConnection.GetDataItem(index);
  1233. }
  1234. }
  1235. #endregion SelectedIndex
  1236. #region SelectedItem
  1237. /// <summary>
  1238. /// Gets or sets the first item in the current selection or returns null if the selection is empty.
  1239. /// </summary>
  1240. public object SelectedItem
  1241. {
  1242. get { return GetValue(SelectedItemProperty) as object; }
  1243. set { SetValue(SelectedItemProperty, value); }
  1244. }
  1245. /// <summary>
  1246. /// Identifies the SelectedItem dependency property.
  1247. /// </summary>
  1248. public static readonly DependencyProperty SelectedItemProperty =
  1249. DependencyProperty.Register(
  1250. "SelectedItem",
  1251. typeof(object),
  1252. typeof(DataGrid),
  1253. new PropertyMetadata(OnSelectedItemPropertyChanged));
  1254. /// <summary>
  1255. /// SelectedItemProperty property changed handler.
  1256. /// </summary>
  1257. /// <param name="d">DataGrid that changed its SelectedItem.</param>
  1258. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  1259. private static void OnSelectedItemPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  1260. {
  1261. DataGrid dataGrid = (DataGrid)d;
  1262. if (!dataGrid.IsHandlerSuspended(e.Property))
  1263. {
  1264. int rowIndex = (e.NewValue == null) ? -1 : dataGrid.DataConnection.IndexOf(e.NewValue);
  1265. if (rowIndex == -1)
  1266. {
  1267. // If the Item is null or it's not found, clear the Selection
  1268. if (!dataGrid.CommitEdit(DataGridEditingUnit.Row, true /*exitEditing*/))
  1269. {
  1270. // Edited value couldn't be committed or aborted
  1271. d.SetValueNoCallback(e.Property, e.OldValue);
  1272. throw DataGridError.DataGrid.CommitFailedCannotCompleteOperation();
  1273. }
  1274. // Clear all row selections
  1275. dataGrid.ClearRowSelection(true /*resetAnchorRowIndex*/);
  1276. }
  1277. else
  1278. {
  1279. dataGrid.SetValueNoCallback(DataGrid.SelectedIndexProperty, rowIndex);
  1280. if (rowIndex != dataGrid.CurrentRowIndex)
  1281. {
  1282. if (!dataGrid.CommitEdit(DataGridEditingUnit.Row, true /*exitEditing*/))
  1283. {
  1284. // Edited value couldn't be committed or aborted
  1285. d.SetValueNoCallback(e.Property, e.OldValue);
  1286. throw DataGridError.DataGrid.CommitFailedCannotCompleteOperation();
  1287. }
  1288. if (dataGrid.IsRowOutOfBounds(rowIndex))
  1289. {
  1290. return;
  1291. }
  1292. }
  1293. try
  1294. {
  1295. dataGrid._noSelectionChangeCount++;
  1296. dataGrid.ClearRowSelection(rowIndex /*rowIndexException*/, true /*resetAnchorRowIndex*/);
  1297. int columnIndex = dataGrid.CurrentColumnIndex;
  1298. if (columnIndex == -1)
  1299. {
  1300. columnIndex = dataGrid.ColumnsInternal.FirstVisibleColumn == null ? -1 : dataGrid.ColumnsInternal.FirstVisibleColumn.Index;
  1301. }
  1302. if (columnIndex == -1 || dataGrid.IsRowOutOfBounds(rowIndex))
  1303. {
  1304. return;
  1305. }
  1306. bool success = dataGrid.SetCurrentCellCore(columnIndex, rowIndex/*, false, false*/);
  1307. Debug.Assert(success);
  1308. }
  1309. finally
  1310. {
  1311. dataGrid.NoSelectionChangeCount--;
  1312. }
  1313. }
  1314. }
  1315. }
  1316. #endregion SelectedItem
  1317. #region VerticalGridLinesBrush
  1318. /// <summary>
  1319. /// Gets or sets a brush that describes the vertical gridlines color.
  1320. /// </summary>
  1321. public Brush VerticalGridLinesBrush
  1322. {
  1323. get { return GetValue(VerticalGridLinesBrushProperty) as Brush; }
  1324. set { SetValue(VerticalGridLinesBrushProperty, value); }
  1325. }
  1326. /// <summary>
  1327. /// Identifies the VerticalGridLinesBrush dependency property.
  1328. /// </summary>
  1329. public static readonly DependencyProperty VerticalGridLinesBrushProperty =
  1330. DependencyProperty.Register(
  1331. "VerticalGridLinesBrush",
  1332. typeof(Brush),
  1333. typeof(DataGrid),
  1334. new PropertyMetadata(OnVerticalGridLinesBrushPropertyChanged));
  1335. /// <summary>
  1336. /// VerticalGridLinesBrushProperty property changed handler.
  1337. /// </summary>
  1338. /// <param name="d">DataGrid that changed its VerticalGridLinesBrush.</param>
  1339. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  1340. private static void OnVerticalGridLinesBrushPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  1341. {
  1342. DataGrid dataGrid = (DataGrid)d;
  1343. if (!dataGrid.IsHandlerSuspended(e.Property) && dataGrid._rowsPresenter != null)
  1344. {
  1345. foreach (DataGridRow row in dataGrid._rowsPresenter.Children)
  1346. {
  1347. row.EnsureGridLines();
  1348. }
  1349. }
  1350. }
  1351. #endregion VerticalGridLinesBrush
  1352. #region VerticalScrollBarVisibility
  1353. /// <summary>
  1354. /// Gets or sets a value that indicates whether a vertical ScrollBar should be displayed.
  1355. /// </summary>
  1356. public ScrollBarVisibility VerticalScrollBarVisibility
  1357. {
  1358. get { return (ScrollBarVisibility)GetValue(VerticalScrollBarVisibilityProperty); }
  1359. set { SetValue(VerticalScrollBarVisibilityProperty, value); }
  1360. }
  1361. /// <summary>
  1362. /// Identifies the VerticalScrollBarVisibility dependency property.
  1363. /// </summary>
  1364. public static readonly DependencyProperty VerticalScrollBarVisibilityProperty =
  1365. DependencyProperty.Register(
  1366. "VerticalScrollBarVisibility",
  1367. typeof(ScrollBarVisibility),
  1368. typeof(DataGrid),
  1369. new PropertyMetadata(OnVerticalScrollBarVisibilityPropertyChanged));
  1370. /// <summary>
  1371. /// VerticalScrollBarVisibilityProperty property changed handler.
  1372. /// </summary>
  1373. /// <param name="d">DataGrid that changed its VerticalScrollBarVisibility.</param>
  1374. /// <param name="e">DependencyPropertyChangedEventArgs.</param>
  1375. private static void OnVerticalScrollBarVisibilityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  1376. {
  1377. DataGrid dataGrid = (DataGrid)d;
  1378. if (!dataGrid.IsHandlerSuspended(e.Property) &&
  1379. (ScrollBarVisibility)e.NewValue != (ScrollBarVisibility)e.OldValue &&
  1380. dataGrid._vScrollBar != null)
  1381. {
  1382. dataGrid.InvalidateMeasure();
  1383. }
  1384. }
  1385. #endregion VerticalScrollBarVisibility
  1386. #endregion Dependency Properties
  1387. #region Public Properties
  1388. //
  1389. /// <summary>
  1390. /// Gets the collection of columns currently present in the DataGrid.
  1391. /// </summary>
  1392. public ObservableCollection<DataGridColumn> Columns
  1393. {
  1394. get
  1395. {
  1396. // we use a backing field here because the field's type
  1397. // is a subclass of the property's
  1398. return this.ColumnsInternal;
  1399. }
  1400. }
  1401. /// <summary>
  1402. /// Gets or sets the column that contains the cell that will go into
  1403. /// editing mode.
  1404. /// </summary>
  1405. public DataGridColumn CurrentColumn
  1406. {
  1407. get
  1408. {
  1409. if (this.CurrentColumnIndex == -1)
  1410. {
  1411. return null;
  1412. }
  1413. Debug.Assert(this.CurrentColumnIndex < this.Columns.Count);
  1414. return this.Columns[this.CurrentColumnIndex];
  1415. }
  1416. set
  1417. {
  1418. DataGridColumn dataGridColumn = value;
  1419. if (dataGridColumn == null)
  1420. {
  1421. throw DataGridError.DataGrid.ValueCannotBeSetToNull("value", "CurrentColumn");
  1422. }
  1423. if (this.CurrentColumn != dataGridColumn)
  1424. {
  1425. if (dataGridColumn.OwningGrid != this)
  1426. {
  1427. // Provided column does not belong to this DataGrid
  1428. throw DataGridError.DataGrid.ColumnNotInThisDataGrid();
  1429. }
  1430. if (dataGridColumn.Visibility == Visibility.Collapsed)
  1431. {
  1432. // CurrentColumn cannot be set to an invisible column
  1433. throw DataGridError.DataGrid.ColumnCannotBeCollapsed();
  1434. }
  1435. if (this.CurrentRowIndex == -1)
  1436. {
  1437. // There is no current row so the current column cannot be set
  1438. throw DataGridError.DataGrid.NoCurrentRow();
  1439. }
  1440. bool beginEdit = this._editingColumnIndex != -1;
  1441. if (!EndCellEdit(true /*commitCellEdit*/, true /*exitEditingMode*/, this.ContainsFocus /*keepFocus*/))
  1442. {
  1443. // Edited value couldn't be committed or aborted
  1444. throw DataGridError.DataGrid.CommitFailedCannotCompleteOperation();
  1445. }
  1446. bool success = SetCurrentCellCore(dataGridColumn.Index, this.CurrentRowIndex);
  1447. Debug.Assert(success);
  1448. if (beginEdit &&
  1449. this._editingColumnIndex == -1 &&
  1450. this.CurrentRowIndex != -1 &&
  1451. this.CurrentColumnIndex != -1 &&
  1452. this.CurrentColumnIndex == dataGridColumn.Index &&
  1453. dataGridColumn.OwningGrid == this &&
  1454. !GetColumnEffectiveReadOnlyState(dataGridColumn))
  1455. {
  1456. // Returning to editing mode since the grid was in that mode prior to the EndCellEdit call above.
  1457. BeginCellEdit(new RoutedEventArgs());
  1458. }
  1459. }
  1460. }
  1461. }
  1462. /*
  1463. */
  1464. //
  1465. /*
  1466. */
  1467. /// <summary>
  1468. /// Gets the currently selected items.
  1469. /// </summary>
  1470. public IList SelectedItems
  1471. {
  1472. get { return _selectedItems as IList; }
  1473. }
  1474. #endregion Public Properties
  1475. #region Protected Properties
  1476. /// <summary>
  1477. /// Gets the item that will be edited during editing mode.
  1478. /// </summary>
  1479. protected object CurrentItem
  1480. {
  1481. get
  1482. {
  1483. if (this.CurrentRowIndex == -1 || this.ItemsSource /*this.DataConnection.DataSource*/ == null)
  1484. {
  1485. return null;
  1486. }
  1487. return this.DataConnection.GetDataItem(this.CurrentRowIndex);
  1488. }
  1489. //
  1490. }
  1491. #endregion Protected Properties
  1492. #region Internal Properties
  1493. internal int AnchorRowIndex
  1494. {
  1495. get;
  1496. private set;
  1497. }
  1498. internal double ActualRowHeaderWidth
  1499. {
  1500. get
  1501. {
  1502. if (!this.AreRowHeadersVisible)
  1503. {
  1504. return 0;
  1505. }
  1506. else
  1507. {
  1508. return !double.IsNaN(this.RowHeaderWidth) ? this.RowHeaderWidth : this.RowHeadersDesiredWidth;
  1509. }
  1510. }
  1511. }
  1512. internal bool AreColumnHeadersVisible
  1513. {
  1514. get
  1515. {
  1516. return (this.HeadersVisibility & DataGridHeadersVisibility.Column) == DataGridHeadersVisibility.Column;
  1517. }
  1518. }
  1519. internal bool AreRowHeadersVisible
  1520. {
  1521. get
  1522. {
  1523. return (this.HeadersVisibility & DataGridHeadersVisibility.Row) == DataGridHeadersVisibility.Row;
  1524. }
  1525. }
  1526. internal double AvailableRowRoom
  1527. {
  1528. get;
  1529. set;
  1530. }
  1531. //
  1532. // Height currently available for cells this value is smaller. This height is reduced by the existence of ColumnHeaders
  1533. // or a horizontal scrollbar. Layout is asynchronous so changes to the ColumnHeaders or the horizontal scrollbar are
  1534. // not reflected immediately.
  1535. internal double CellsHeight
  1536. {
  1537. get
  1538. {
  1539. return this.RowsPresenterAvailableSize.Height;
  1540. }
  1541. }
  1542. // Width currently available for cells this value is smaller. This width is reduced by the existence of RowHeaders
  1543. // or a vertical scrollbar. Layout is asynchronous so changes to the RowHeaders or the vertical scrollbar are
  1544. // not reflected immediately
  1545. internal double CellsWidth
  1546. {
  1547. get
  1548. {
  1549. if (double.IsPositiveInfinity(this.RowsPresenterAvailableSize.Width))
  1550. {
  1551. // If we're given infinite width, then the cells will just grow to be as big as the columns
  1552. return this.ColumnsInternal.VisibleEdgedColumnsWidth;
  1553. }
  1554. else
  1555. {
  1556. return Math.Max(0, this.RowsPresenterAvailableSize.Width - this.ActualRowHeaderWidth);
  1557. }
  1558. }
  1559. }
  1560. internal DataGridColumnHeadersPresenter ColumnHeaders
  1561. {
  1562. get
  1563. {
  1564. return this._columnHeadersPresenter;
  1565. }
  1566. }
  1567. //
  1568. internal DataGridColumnCollection ColumnsInternal
  1569. {
  1570. get;
  1571. private set;
  1572. }
  1573. internal List<DataGridColumn> ColumnsItemsInternal
  1574. {
  1575. get
  1576. {
  1577. return this.ColumnsInternal.ItemsInternal;
  1578. }
  1579. }
  1580. internal Popup ColumnDropLocationIndicatorPopup
  1581. {
  1582. get
  1583. {
  1584. if (this._columnDropLocationIndicatorPopup == null)
  1585. {
  1586. this._columnDropLocationIndicatorPopup = new Popup
  1587. {
  1588. Child = this.ColumnDropLocationIndicator,
  1589. IsOpen = false
  1590. };
  1591. }
  1592. return this._columnDropLocationIndicatorPopup;
  1593. }
  1594. }
  1595. internal Control ColumnDropLocationIndicator
  1596. {
  1597. get
  1598. {
  1599. //
  1600. if (this._columnDropLocationIndicator == null ||
  1601. this._columnDropLocationIndicator.Style != this.DropLocationIndicatorStyle)
  1602. {
  1603. this._columnDropLocationIndicator = new ContentControl();
  1604. this._columnDropLocationIndicator.Style = this.DropLocationIndicatorStyle;
  1605. }
  1606. return this._columnDropLocationIndicator;
  1607. }
  1608. }
  1609. internal bool ContainsFocus
  1610. {
  1611. get;
  1612. private set;
  1613. }
  1614. internal int CurrentColumnIndex
  1615. {
  1616. get
  1617. {
  1618. return this.CurrentCellCoordinates.ColumnIndex;
  1619. }
  1620. private set
  1621. {
  1622. this.CurrentCellCoordinates.ColumnIndex = value;
  1623. }
  1624. }
  1625. internal int CurrentRowIndex
  1626. {
  1627. get
  1628. {
  1629. return this.CurrentCellCoordinates.RowIndex;
  1630. }
  1631. private set
  1632. {
  1633. this.CurrentCellCoordinates.RowIndex = value;
  1634. }
  1635. }
  1636. internal DataGridDataConnection DataConnection
  1637. {
  1638. get;
  1639. private set;
  1640. }
  1641. internal DataGridDisplayData DisplayData
  1642. {
  1643. get;
  1644. private set;
  1645. }
  1646. internal int EditingColumnIndex
  1647. {
  1648. get
  1649. {
  1650. return this._editingColumnIndex;
  1651. }
  1652. }
  1653. internal int? EditingRowIndex
  1654. {
  1655. get
  1656. {
  1657. if (this._editingRow == null)
  1658. {
  1659. return null;
  1660. }
  1661. else
  1662. {
  1663. return this._editingRow.Index;
  1664. }
  1665. }
  1666. }
  1667. internal double FirstDisplayedScrollingColumnHiddenWidth
  1668. {
  1669. get
  1670. {
  1671. return this._negHorizontalOffset;
  1672. }
  1673. }
  1674. internal static double HorizontalGridLinesThickness
  1675. {
  1676. get
  1677. {
  1678. return DATAGRID_horizontalGridLinesThickness;
  1679. }
  1680. }
  1681. // the sum of the widths in pixels of the scrolling columns preceding
  1682. // the first displayed scrolling column
  1683. internal double HorizontalOffset
  1684. {
  1685. get
  1686. {
  1687. return this._horizontalOffset;
  1688. }
  1689. set
  1690. {
  1691. if (value < 0)
  1692. {
  1693. value = 0;
  1694. }
  1695. double widthNotVisible = Math.Max(0, this.ColumnsInternal.VisibleEdgedColumnsWidth - this.CellsWidth);
  1696. if (value > widthNotVisible)
  1697. {
  1698. value = widthNotVisible;
  1699. }
  1700. if (value == this._horizontalOffset)
  1701. {
  1702. return;
  1703. }
  1704. if (this._hScrollBar != null && value != this._hScrollBar.Value)
  1705. {
  1706. this._hScrollBar.Value = value;
  1707. }
  1708. this._horizontalOffset = value;
  1709. this.DisplayData.FirstDisplayedScrollingCol = ComputeFirstVisibleScrollingColumn();
  1710. // update the lastTotallyDisplayedScrollingCol
  1711. ComputeDisplayedColumns();
  1712. }
  1713. }
  1714. internal ScrollBar HorizontalScrollBar
  1715. {
  1716. get
  1717. {
  1718. return _hScrollBar;
  1719. }
  1720. }
  1721. internal bool LoadingOrUnloadingRow
  1722. {
  1723. get;
  1724. private set;
  1725. }
  1726. internal bool InDisplayIndexAdjustments
  1727. {
  1728. get;
  1729. set;
  1730. }
  1731. internal int? MouseOverRowIndex
  1732. {
  1733. get
  1734. {
  1735. return this._mouseOverRowIndex;
  1736. }
  1737. set
  1738. {
  1739. if (this._mouseOverRowIndex != value)
  1740. {
  1741. DataGridRow oldMouseOverRow = null;
  1742. if (this._mouseOverRowIndex.HasValue && this.DisplayData.IsRowDisplayed(this._mouseOverRowIndex.Value))
  1743. {
  1744. oldMouseOverRow = this.DisplayData.GetDisplayedRow(this._mouseOverRowIndex.Value);
  1745. }
  1746. this._mouseOverRowIndex = value;
  1747. if (oldMouseOverRow != null)
  1748. {
  1749. oldMouseOverRow.ApplyState(true /*animate*/);
  1750. }
  1751. if (this._mouseOverRowIndex.HasValue && this.DisplayData.IsRowDisplayed(this._mouseOverRowIndex.Value))
  1752. {
  1753. this.DisplayData.GetDisplayedRow(this._mouseOverRowIndex.Value).ApplyState(true /*animate*/);
  1754. }
  1755. }
  1756. }
  1757. }
  1758. internal double NegVerticalOffset
  1759. {
  1760. get;
  1761. private set;
  1762. }
  1763. internal int RowCount
  1764. {
  1765. get;
  1766. private set;
  1767. }
  1768. internal double RowDetailsHeightEstimate
  1769. {
  1770. get;
  1771. private set;
  1772. }
  1773. internal double RowHeadersDesiredWidth
  1774. {
  1775. get
  1776. {
  1777. return _rowHeaderDesiredWidth;
  1778. }
  1779. set
  1780. {
  1781. // We only auto grow
  1782. if (_rowHeaderDesiredWidth < value)
  1783. {
  1784. double oldActualRowHeaderWidth = this.ActualRowHeaderWidth;
  1785. _rowHeaderDesiredWidth = value;
  1786. if (oldActualRowHeaderWidth != this.ActualRowHeaderWidth)
  1787. {
  1788. EnsureRowHeaderWidth();
  1789. }
  1790. }
  1791. }
  1792. }
  1793. internal double RowHeightEstimate
  1794. {
  1795. get;
  1796. private set;
  1797. }
  1798. internal Size RowsPresenterAvailableSize
  1799. {
  1800. get;
  1801. set;
  1802. }
  1803. internal ScrollBar VerticalScrollBar
  1804. {
  1805. get
  1806. {
  1807. return _vScrollBar;
  1808. }
  1809. }
  1810. #endregion Internal Properties
  1811. #region Private Properties
  1812. private DataGridCellCoordinates CurrentCellCoordinates
  1813. {
  1814. get
  1815. {
  1816. return this._currentCellCoordinates;
  1817. }
  1818. set
  1819. {
  1820. this._currentCellCoordinates = value;
  1821. }
  1822. }
  1823. private int FirstDisplayedColumnIndex
  1824. {
  1825. get
  1826. {
  1827. int firstDisplayedColumnIndex = -1;
  1828. DataGridColumn dataGridColumn = this.ColumnsInternal.FirstVisibleColumn;
  1829. if (dataGridColumn != null)
  1830. {
  1831. if (dataGridColumn.IsFrozen)
  1832. {
  1833. firstDisplayedColumnIndex = dataGridColumn.Index;
  1834. }
  1835. else if (this.DisplayData.FirstDisplayedScrollingCol >= 0)
  1836. {
  1837. firstDisplayedColumnIndex = this.DisplayData.FirstDisplayedScrollingCol;
  1838. }
  1839. }
  1840. return firstDisplayedColumnIndex;
  1841. }
  1842. }
  1843. //
  1844. private int NoSelectionChangeCount
  1845. {
  1846. get
  1847. {
  1848. return this._noSelectionChangeCount;
  1849. }
  1850. set
  1851. {
  1852. Debug.Assert(value >= 0);
  1853. this._noSelectionChangeCount = value;
  1854. if (value == 0)
  1855. {
  1856. FlushSelectionChanged();
  1857. }
  1858. }
  1859. }
  1860. #endregion Private Properties
  1861. #region Public Methods
  1862. /// <summary>
  1863. /// Enters editing mode for the current cell and current row (if they're not already in editing mode).
  1864. /// </summary>
  1865. /// <returns>True if operation was successful. False otherwise.</returns>
  1866. public bool BeginEdit()
  1867. {
  1868. return BeginEdit(null);
  1869. }
  1870. /// <summary>
  1871. /// Enters editing mode for the current cell and current row (if they're not already in editing mode).
  1872. /// </summary>
  1873. /// <param name="editingEventArgs">Provides information about the user gesture that caused the call to BeginEdit. Can be null.</param>
  1874. /// <returns>True if operation was successful. False otherwise.</returns>
  1875. public bool BeginEdit(RoutedEventArgs editingEventArgs)
  1876. {
  1877. //
  1878. if (this.CurrentColumnIndex == -1 || !GetRowSelection(this.CurrentRowIndex))
  1879. {
  1880. //
  1881. return false;
  1882. }
  1883. Debug.Assert(this.CurrentColumnIndex >= 0);
  1884. Debug.Assert(this.CurrentColumnIndex < this.Columns.Count);
  1885. Debug.Assert(this.CurrentRowIndex >= -1);
  1886. Debug.Assert(this.CurrentRowIndex < this.RowCount);
  1887. Debug.Assert(this._editingRow == null || this.EditingRowIndex == this.CurrentRowIndex);
  1888. if (GetColumnEffectiveReadOnlyState(this.CurrentColumn))
  1889. {
  1890. // Current column is read-only
  1891. //
  1892. return false;
  1893. }
  1894. //
  1895. return BeginCellEdit(editingEventArgs);
  1896. }
  1897. /// <summary>
  1898. /// Cancels editing mode for the specified DataGridEditingUnit and restores its original value.
  1899. /// </summary>
  1900. /// <param name="editingUnit">Specifies whether to cancel edit for a Cell or Row.</param>
  1901. /// <returns>True if operation was successful. False otherwise.</returns>
  1902. public bool CancelEdit(DataGridEditingUnit editingUnit)
  1903. {
  1904. if (!EndCellEdit(false, true, this.ContainsFocus /*keepFocus*/))
  1905. {
  1906. return false;
  1907. }
  1908. if (editingUnit == DataGridEditingUnit.Row)
  1909. {
  1910. return EndRowEdit(false, true);
  1911. }
  1912. return true;
  1913. }
  1914. /// <summary>
  1915. /// Commits editing mode for the specified DataGridEditingUnit and pushes changes to the backend.
  1916. /// </summary>
  1917. /// <param name="editingUnit">Specifies whether to commit edit for a Cell or Row.</param>
  1918. /// <param name="exitEditingMode">Editing mode is left if True.</param>
  1919. /// <returns>True if operation was successful. False otherwise.</returns>
  1920. public bool CommitEdit(DataGridEditingUnit editingUnit, bool exitEditingMode)
  1921. {
  1922. if (!EndCellEdit(true, exitEditingMode, this.ContainsFocus /*keepFocus*/))
  1923. {
  1924. return false;
  1925. }
  1926. if (editingUnit == DataGridEditingUnit.Row)
  1927. {
  1928. return EndRowEdit(true, exitEditingMode);
  1929. }
  1930. return true;
  1931. }
  1932. /// <summary>
  1933. /// Scrolls the specified item and/or column into view.
  1934. /// If item is not null: scrolls the row representing the item into view;
  1935. /// If column is not null: scrolls the column into view;
  1936. /// If both item and column are null, the method returns without scrolling.
  1937. /// </summary>
  1938. /// <param name="item">an item from the DataGrid's items source</param>
  1939. /// <param name="column">a column from the DataGrid's columns collection</param>
  1940. public void ScrollIntoView(object item, DataGridColumn column)
  1941. {
  1942. if (item == null && column == null)
  1943. {
  1944. // no-op
  1945. return;
  1946. }
  1947. // the row index will be set to -1 if the item is null or not in the list
  1948. int rowIndex = this.DataConnection.IndexOf(item);
  1949. if (item != null && rowIndex == -1)
  1950. {
  1951. return;
  1952. }
  1953. // the column, if non-null, must be owned by this grid
  1954. if (column != null && column.OwningGrid != this)
  1955. {
  1956. // invalid
  1957. return;
  1958. }
  1959. // dispatch
  1960. if (item != null && column == null)
  1961. {
  1962. // scroll row into view
  1963. this.ScrollIntoView(this.FirstDisplayedColumnIndex, rowIndex, true);
  1964. }
  1965. else if (item == null && column != null)
  1966. {
  1967. // scroll column into view
  1968. this.ScrollIntoView(column.Index, this.DisplayData.FirstDisplayedScrollingRow, false);
  1969. }
  1970. else if (item != null && column != null)
  1971. {
  1972. // scroll cell into view
  1973. this.ScrollIntoView(column.Index, rowIndex, true);
  1974. }
  1975. }
  1976. #endregion Public Methods
  1977. #region Protected Methods
  1978. protected override Size ArrangeOverride(Size finalSize)
  1979. {
  1980. if (_makeFirstDisplayedCellCurrentCellPending)
  1981. {
  1982. MakeFirstDisplayedCellCurrentCell();
  1983. }
  1984. if (this.ActualWidth != finalSize.Width)
  1985. {
  1986. // If our final width has changed, we might need to update the filler
  1987. InvalidateColumnHeadersArrange();
  1988. InvalidateCellsArrange();
  1989. }
  1990. return base.ArrangeOverride(finalSize);
  1991. }
  1992. protected override Size MeasureOverride(Size availableSize)
  1993. {
  1994. // Delay column autogeneration till the after the inital measure to avoid generating columns if
  1995. // the user does dataGrid.ItemsSource = myList; dataGrid.AutogenerateColumns = false;
  1996. if (!_measured)
  1997. {
  1998. _measured = true;
  1999. if (this.AutoGenerateColumns)
  2000. {
  2001. RefreshRowsAndColumns();
  2002. }
  2003. // Update our estimates now that the DataGrid has all of the information necessary
  2004. UpdateRowDetailsHeightEstimate();
  2005. // Update frozen columns to account for columns added prior to loading or autogenerated columns
  2006. if (this.FrozenColumnCount > 0)
  2007. {
  2008. ProcessFrozenColumnCount(this);
  2009. }
  2010. }
  2011. Size desiredSize;
  2012. // This is a shortcut to skip layout if we don't have any columns
  2013. if (this.ColumnsInternal.VisibleEdgedColumnsWidth == 0)
  2014. {
  2015. if (_hScrollBar != null && _hScrollBar.Visibility != Visibility.Collapsed)
  2016. {
  2017. _hScrollBar.Visibility = Visibility.Collapsed;
  2018. }
  2019. if (_vScrollBar != null && _vScrollBar.Visibility != Visibility.Collapsed)
  2020. {
  2021. _vScrollBar.Visibility = Visibility.Collapsed;
  2022. }
  2023. desiredSize = base.MeasureOverride(availableSize);
  2024. }
  2025. else
  2026. {
  2027. if (_rowsPresenter != null)
  2028. {
  2029. _rowsPresenter.InvalidateMeasure();
  2030. }
  2031. InvalidateColumnHeadersMeasure();
  2032. desiredSize = base.MeasureOverride(availableSize);
  2033. //
  2034. ComputeScrollBarsLayout();
  2035. }
  2036. return desiredSize;
  2037. }
  2038. public override void OnApplyTemplate()
  2039. {
  2040. _columnHeadersPresenter = GetTemplateChild(DATAGRID_elementColumnHeadersPresenterName) as DataGridColumnHeadersPresenter;
  2041. if (_columnHeadersPresenter != null)
  2042. {
  2043. _columnHeadersPresenter.OwningGrid = this;
  2044. // Columns were added before before our Template was applied, add the ColumnHeaders now
  2045. foreach (DataGridColumn column in this.ColumnsInternal)
  2046. {
  2047. InsertDisplayedColumnHeader(column);
  2048. }
  2049. }
  2050. _rowsPresenter = GetTemplateChild(DATAGRID_elementRowsPresenterName) as DataGridRowsPresenter;
  2051. if (_rowsPresenter != null)
  2052. {
  2053. _rowsPresenter.OwningGrid = this;
  2054. InvalidateRowHeightEstimate();
  2055. UpdateRowDetailsHeightEstimate();
  2056. }
  2057. _frozenColumnScrollBarSpacer = GetTemplateChild(DATAGRID_elementFrozenColumnScrollBarSpacerName) as FrameworkElement;
  2058. _hScrollBar = GetTemplateChild(DATAGRID_elementHorizontalScrollbarName) as ScrollBar;
  2059. if (_hScrollBar != null)
  2060. {
  2061. _hScrollBar.IsTabStop = false;
  2062. _hScrollBar.Maximum = 0.0;
  2063. _hScrollBar.Orientation = Orientation.Horizontal;
  2064. _hScrollBar.Visibility = Visibility.Collapsed;
  2065. _hScrollBar.Scroll += new ScrollEventHandler(HorizontalScrollBar_Scroll);
  2066. }
  2067. _vScrollBar = GetTemplateChild(DATAGRID_elementVerticalScrollbarName) as ScrollBar;
  2068. if (_vScrollBar != null)
  2069. {
  2070. _vScrollBar.IsTabStop = false;
  2071. _vScrollBar.Maximum = 0.0;
  2072. _vScrollBar.Orientation = Orientation.Vertical;
  2073. _vScrollBar.Visibility = Visibility.Collapsed;
  2074. _vScrollBar.Scroll += new ScrollEventHandler(VerticalScrollBar_Scroll);
  2075. }
  2076. _topLeftCornerHeader = GetTemplateChild(DATAGRID_elementTopLeftCornerHeaderName) as ContentControl;
  2077. EnsureTopLeftCornerHeader(); // EnsureTopLeftCornerHeader checks for a null _topLeftCornerHeader;
  2078. _topRightCornerHeader = GetTemplateChild(DATAGRID_elementTopRightCornerHeaderName) as ContentControl;
  2079. }
  2080. /// <summary>
  2081. /// Raises the AutoGeneratingColumn event.
  2082. /// </summary>
  2083. protected virtual void OnAutoGeneratingColumn(DataGridAutoGeneratingColumnEventArgs e)
  2084. {
  2085. EventHandler<DataGridAutoGeneratingColumnEventArgs> handler = this.AutoGeneratingColumn;
  2086. if (handler != null)
  2087. {
  2088. handler(this, e);
  2089. }
  2090. }
  2091. /// <summary>
  2092. /// Raises the BeginningEdit event.
  2093. /// </summary>
  2094. protected virtual void OnBeginningEdit(DataGridBeginningEditEventArgs e)
  2095. {
  2096. EventHandler<DataGridBeginningEditEventArgs> handler = this.BeginningEdit;
  2097. if (handler != null)
  2098. {
  2099. handler(this, e);
  2100. }
  2101. }
  2102. //
  2103. //
  2104. /// <summary>
  2105. /// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
  2106. /// </summary>
  2107. protected override AutomationPeer OnCreateAutomationPeer()
  2108. {
  2109. return new DataGridAutomationPeer(this);
  2110. }
  2111. /// <summary>
  2112. /// Raises the CurrentCellChanged event.
  2113. /// </summary>
  2114. protected virtual void OnCurrentCellChanged(EventArgs e)
  2115. {
  2116. EventHandler<EventArgs> handler = this.CurrentCellChanged;
  2117. if (handler != null)
  2118. {
  2119. handler(this, e);
  2120. }
  2121. if (AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementSelected))
  2122. {
  2123. DataGridAutomationPeer peer = DataGridAutomationPeer.FromElement(this) as DataGridAutomationPeer;
  2124. if (peer != null)
  2125. {
  2126. peer.RaiseAutomationCellSelectedEvent(this.CurrentRowIndex, this.CurrentColumnIndex);
  2127. }
  2128. }
  2129. }
  2130. /// <summary>
  2131. /// Raises the PreparingCellForEdit event.
  2132. /// </summary>
  2133. protected virtual void OnPreparingCellForEdit(DataGridPreparingCellForEditEventArgs e)
  2134. {
  2135. EventHandler<DataGridPreparingCellForEditEventArgs> handler = this.PreparingCellForEdit;
  2136. if (handler != null)
  2137. {
  2138. handler(this, e);
  2139. }
  2140. // Raise the automation invoke event for the cell that just began edit because now
  2141. // its editable content has been loaded
  2142. DataGridAutomationPeer peer = DataGridAutomationPeer.FromElement(this) as DataGridAutomationPeer;
  2143. if (peer != null && AutomationPeer.ListenerExists(AutomationEvents.InvokePatternOnInvoked))
  2144. {
  2145. peer.RaiseAutomationInvokeEvents(DataGridEditingUnit.Cell, e.Column, e.Row);
  2146. }
  2147. }
  2148. /// <summary>
  2149. /// Raises the LoadingRow event for row preparation.
  2150. /// </summary>
  2151. protected virtual void OnLoadingRow(DataGridRowEventArgs e)
  2152. {
  2153. EventHandler<DataGridRowEventArgs> handler = this.LoadingRow;
  2154. if (handler != null)
  2155. {
  2156. Debug.Assert(!this._loadedRows.Contains(e.Row));
  2157. this._loadedRows.Add(e.Row);
  2158. this.LoadingOrUnloadingRow = true;
  2159. handler(this, e);
  2160. this.LoadingOrUnloadingRow = false;
  2161. Debug.Assert(this._loadedRows.Contains(e.Row));
  2162. this._loadedRows.Remove(e.Row);
  2163. }
  2164. }
  2165. /// <summary>
  2166. /// Raises the LoadingRowDetails for row details preparation
  2167. /// </summary>
  2168. protected virtual void OnLoadingRowDetails(DataGridRowDetailsEventArgs e)
  2169. {
  2170. EventHandler<DataGridRowDetailsEventArgs> handler = this.LoadingRowDetails;
  2171. if (handler != null)
  2172. {
  2173. this.LoadingOrUnloadingRow = true;
  2174. handler(this, e);
  2175. this.LoadingOrUnloadingRow = false;
  2176. }
  2177. }
  2178. /// <summary>
  2179. /// Raises the SelectionChanged event and clears the _selectionChanged.
  2180. /// This event won't get raised again until after _selectionChanged is set back to true.
  2181. /// </summary>
  2182. protected virtual void OnSelectionChanged(SelectionChangedEventArgs e)
  2183. {
  2184. this.CoerceSelectedItem();
  2185. this._selectionChanged = false;
  2186. SelectionChangedEventHandler handler = this.SelectionChanged;
  2187. if (handler != null)
  2188. {
  2189. handler(this, e);
  2190. }
  2191. if (AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementSelected) ||
  2192. AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementAddedToSelection) ||
  2193. AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementRemovedFromSelection))
  2194. {
  2195. DataGridAutomationPeer peer = DataGridAutomationPeer.FromElement(this) as DataGridAutomationPeer;
  2196. if (peer != null)
  2197. {
  2198. peer.RaiseAutomationSelectionEvents(e);
  2199. }
  2200. }
  2201. }
  2202. /// <summary>
  2203. /// Raises the UnloadingRow event for row recycling.
  2204. /// </summary>
  2205. protected virtual void OnUnloadingRow(DataGridRowEventArgs e)
  2206. {
  2207. EventHandler<DataGridRowEventArgs> handler = this.UnloadingRow;
  2208. if (handler != null)
  2209. {
  2210. this.LoadingOrUnloadingRow = true;
  2211. handler(this, e);
  2212. this.LoadingOrUnloadingRow = false;
  2213. }
  2214. }
  2215. /// <summary>
  2216. /// Raises the UnloadingRowDetails event
  2217. /// </summary>
  2218. protected virtual void OnUnloadingRowDetails(DataGridRowDetailsEventArgs e)
  2219. {
  2220. EventHandler<DataGridRowDetailsEventArgs> handler = this.UnloadingRowDetails;
  2221. if (handler != null)
  2222. {
  2223. this.LoadingOrUnloadingRow = true;
  2224. handler(this, e);
  2225. this.LoadingOrUnloadingRow = false;
  2226. }
  2227. }
  2228. #endregion Protected Methods
  2229. #region Internal Methods
  2230. /// <summary>
  2231. /// call when: selection changes or SelectedItems object changes
  2232. /// </summary>
  2233. internal void CoerceSelectedItem()
  2234. {
  2235. object selectedItem = null;
  2236. if (this.SelectionMode == DataGridSelectionMode.Extended &&
  2237. this.CurrentRowIndex != -1 &&
  2238. _selectedItems.Contains(this.CurrentRowIndex))
  2239. {
  2240. selectedItem = this.CurrentItem;
  2241. }
  2242. else if (_selectedItems.Count > 0)
  2243. {
  2244. selectedItem = _selectedItems[0];
  2245. }
  2246. this.SetValueNoCallback(SelectedItemProperty, selectedItem);
  2247. // Update the SelectedIndex
  2248. int newIndex = -1;
  2249. if (selectedItem != null)
  2250. {
  2251. newIndex = this.DataConnection.IndexOf(selectedItem);
  2252. }
  2253. this.SetValueNoCallback(SelectedIndexProperty, newIndex);
  2254. }
  2255. internal static DataGridCell GetOwningCell(FrameworkElement element)
  2256. {
  2257. Debug.Assert(element != null);
  2258. DataGridCell cell = element as DataGridCell;
  2259. while (element != null && cell == null)
  2260. {
  2261. element = element.Parent as FrameworkElement;
  2262. cell = element as DataGridCell;
  2263. }
  2264. return cell;
  2265. }
  2266. //
  2267. internal void OnAddedSelectedItem(int rowIndex)
  2268. {
  2269. object item = this.DataConnection.GetDataItem(rowIndex);
  2270. Debug.Assert(item != null);
  2271. if (this._removedSelectedItems.Contains(item))
  2272. {
  2273. this._removedSelectedItems.Remove(item);
  2274. }
  2275. else if (!this._selectedItems.Contains(rowIndex) && !this._addedSelectedItems.Contains(item))
  2276. {
  2277. this._addedSelectedItems.Add(item);
  2278. }
  2279. }
  2280. internal void OnRemovedSelectedItem(int rowIndex)
  2281. {
  2282. OnRemovedSelectedItem(rowIndex, this.DataConnection.GetDataItem(rowIndex));
  2283. }
  2284. internal void OnRemovedSelectedItem(int rowIndex, object item)
  2285. {
  2286. if (this._addedSelectedItems.Contains(item))
  2287. {
  2288. this._addedSelectedItems.Remove(item);
  2289. }
  2290. else if (this._selectedItems.Contains(rowIndex) && !this._removedSelectedItems.Contains(item))
  2291. {
  2292. this._removedSelectedItems.Add(item);
  2293. }
  2294. }
  2295. internal void OnRowDetailsChanged()
  2296. {
  2297. // Update layout when RowDetails are expanded or collapsed, just updating the vertical scroll bar is not enough
  2298. // since rows could be added or removed
  2299. InvalidateMeasure();
  2300. }
  2301. internal bool ProcessDownKey()
  2302. {
  2303. bool moved, shift, ctrl;
  2304. KeyboardHelper.GetMetaKeyState(out ctrl, out shift);
  2305. return ProcessDownKeyInternal(shift, ctrl, out moved);
  2306. }
  2307. internal bool ProcessEndKey()
  2308. {
  2309. bool ctrl;
  2310. bool shift;
  2311. KeyboardHelper.GetMetaKeyState(out ctrl, out shift);
  2312. DataGridColumn dataGridColumn = this.ColumnsInternal.LastVisibleColumn;
  2313. int lastVisibleColumnIndex = (dataGridColumn == null) ? -1 : dataGridColumn.Index;
  2314. int firstRowIndex = this.FirstRowIndex;
  2315. int lastRowIndex = this.LastRowIndex;
  2316. if (lastVisibleColumnIndex == -1 || firstRowIndex == -1)
  2317. {
  2318. return false;
  2319. }
  2320. this._noSelectionChangeCount++;
  2321. try
  2322. {
  2323. if (!ctrl /**/)
  2324. {
  2325. return ProcessRightMost(lastVisibleColumnIndex, firstRowIndex);
  2326. }
  2327. else
  2328. {
  2329. if (!PrepareForScroll(lastVisibleColumnIndex, lastRowIndex, true))
  2330. {
  2331. return false;
  2332. }
  2333. if (shift && this.SelectionMode == DataGridSelectionMode.Extended && this.AnchorRowIndex >= 0)
  2334. {
  2335. ClearRowSelection(lastRowIndex, false /*resetAnchorRowIndex*/);
  2336. SetRowsSelection(this.AnchorRowIndex, lastRowIndex);
  2337. }
  2338. else
  2339. {
  2340. ClearRowSelection(lastRowIndex, true /*resetAnchorRowIndex*/);
  2341. }
  2342. // Scrolling needs to be done after Selection is updated
  2343. if (!ScrollIntoView(lastVisibleColumnIndex, lastRowIndex, true))
  2344. {
  2345. return true;
  2346. }
  2347. if (IsInnerCellOutOfBounds(lastVisibleColumnIndex, lastRowIndex))
  2348. {
  2349. return true;
  2350. }
  2351. bool success = SetCurrentCellCore(lastVisibleColumnIndex, lastRowIndex/*, false, false*/);
  2352. Debug.Assert(success);
  2353. }
  2354. }
  2355. finally
  2356. {
  2357. this.NoSelectionChangeCount--;
  2358. }
  2359. return true;
  2360. }
  2361. internal bool ProcessEnterKey()
  2362. {
  2363. bool ctrl, shift, moved = false, ret = true, endRowEdit = true;
  2364. KeyboardHelper.GetMetaKeyState(out ctrl, out shift);
  2365. if (!ctrl)
  2366. {
  2367. // If Enter was used by a TextBox, we shouldn't handle the key
  2368. TextBox focusedTextBox = FocusManager.GetFocusedElement() as TextBox;
  2369. if (focusedTextBox != null && focusedTextBox.AcceptsReturn)
  2370. {
  2371. return false;
  2372. }
  2373. // Enter behaves like down arrow - it commits the potential editing and goes down one cell.
  2374. endRowEdit = false;
  2375. ret = ProcessDownKeyInternal(false, ctrl, out moved);
  2376. }
  2377. // Try to commit the potential editing
  2378. if (!moved && EndCellEdit(true /*commitCellEdit*/, true /*exitEditingMode*/, true /*keepFocus*/) && endRowEdit && this._editingRow != null)
  2379. {
  2380. EndRowEdit(true /*commitRowEdit*/, true /*exitEditingMode*/);
  2381. }
  2382. return ret;
  2383. }
  2384. internal bool ProcessHomeKey()
  2385. {
  2386. bool ctrl;
  2387. bool shift;
  2388. KeyboardHelper.GetMetaKeyState(out ctrl, out shift);
  2389. DataGridColumn dataGridColumn = this.ColumnsInternal.FirstVisibleColumn;
  2390. int firstVisibleColumnIndex = (dataGridColumn == null) ? -1 : dataGridColumn.Index;
  2391. int firstRowIndex = this.FirstRowIndex;
  2392. if (firstVisibleColumnIndex == -1 || firstRowIndex == -1)
  2393. {
  2394. return false;
  2395. }
  2396. this._noSelectionChangeCount++;
  2397. try
  2398. {
  2399. if (!ctrl /* */)
  2400. {
  2401. return ProcessLeftMost(firstVisibleColumnIndex, firstRowIndex);
  2402. }
  2403. else
  2404. {
  2405. if (!ScrollIntoView(firstVisibleColumnIndex, firstRowIndex, true /* forCurrentCellChange */))
  2406. {
  2407. return true;
  2408. }
  2409. if (IsInnerCellOutOfBounds(firstVisibleColumnIndex, firstRowIndex))
  2410. {
  2411. return true;
  2412. }
  2413. if (shift && this.SelectionMode == DataGridSelectionMode.Extended && this.AnchorRowIndex >= 0)
  2414. {
  2415. ClearRowSelection(firstRowIndex, false /*resetAnchorRowIndex*/);
  2416. SetRowsSelection(firstRowIndex, this.AnchorRowIndex);
  2417. }
  2418. else
  2419. {
  2420. ClearRowSelection(firstRowIndex, true /*resetAnchorRowIndex*/);
  2421. }
  2422. bool success = SetCurrentCellCore(firstVisibleColumnIndex, firstRowIndex/*, false, false*/);
  2423. Debug.Assert(success);
  2424. }
  2425. }
  2426. finally
  2427. {
  2428. this.NoSelectionChangeCount--;
  2429. }
  2430. return true;
  2431. }
  2432. internal void ProcessHorizontalScroll(ScrollEventType scrollEventType)
  2433. {
  2434. if (this._horizontalScrollChangesIgnored > 0)
  2435. {
  2436. return;
  2437. }
  2438. // If the user scrolls with the buttons, we need to update the new value of the scroll bar since we delay
  2439. // this calculation. If they scroll in another other way, the scroll bar's correct value has already been set
  2440. double scrollBarValueDifference = 0;
  2441. if (scrollEventType == ScrollEventType.SmallIncrement)
  2442. {
  2443. scrollBarValueDifference = GetHorizontalSmallScrollIncrease();
  2444. }
  2445. else if (scrollEventType == ScrollEventType.SmallDecrement)
  2446. {
  2447. scrollBarValueDifference = -GetHorizontalSmallScrollDecrease();
  2448. }
  2449. this._horizontalScrollChangesIgnored++;
  2450. try
  2451. {
  2452. if (scrollBarValueDifference != 0)
  2453. {
  2454. Debug.Assert(this._horizontalOffset + scrollBarValueDifference >= 0);
  2455. this._hScrollBar.Value = this._horizontalOffset + scrollBarValueDifference;
  2456. }
  2457. UpdateHorizontalOffset(this._hScrollBar.Value);
  2458. }
  2459. finally
  2460. {
  2461. this._horizontalScrollChangesIgnored--;
  2462. }
  2463. DataGridAutomationPeer peer = DataGridAutomationPeer.FromElement(this) as DataGridAutomationPeer;
  2464. if (peer != null)
  2465. {
  2466. peer.RaiseAutomationScrollEvents();
  2467. }
  2468. }
  2469. internal bool ProcessLeftKey()
  2470. {
  2471. bool success;
  2472. bool ctrl;
  2473. bool shift;
  2474. KeyboardHelper.GetMetaKeyState(out ctrl, out shift);
  2475. DataGridColumn dataGridColumn = this.ColumnsInternal.FirstVisibleColumn;
  2476. int firstVisibleColumnIndex = (dataGridColumn == null) ? -1 : dataGridColumn.Index;
  2477. int firstRowIndex = this.FirstRowIndex;
  2478. if (firstVisibleColumnIndex == -1 || firstRowIndex == -1)
  2479. {
  2480. return false;
  2481. }
  2482. int previousVisibleColumnIndex = -1;
  2483. if (this.CurrentColumnIndex != -1)
  2484. {
  2485. dataGridColumn = this.ColumnsInternal.GetPreviousVisibleColumn(this.Columns[this.CurrentColumnIndex]);
  2486. if (dataGridColumn != null)
  2487. {
  2488. previousVisibleColumnIndex = dataGridColumn.Index;
  2489. }
  2490. }
  2491. this._noSelectionChangeCount++;
  2492. try
  2493. {
  2494. if (ctrl)
  2495. {
  2496. return ProcessLeftMost(firstVisibleColumnIndex, firstRowIndex);
  2497. }
  2498. else
  2499. {
  2500. if (this.CurrentColumnIndex == -1)
  2501. {
  2502. Debug.Assert(_selectedItems.Count == 0);
  2503. SetRowSelection(firstRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  2504. success = ScrollIntoView(firstVisibleColumnIndex, firstRowIndex, false);
  2505. Debug.Assert(success);
  2506. if (IsInnerCellOutOfBounds(firstVisibleColumnIndex, firstRowIndex))
  2507. {
  2508. return true;
  2509. }
  2510. success = SetCurrentCellCore(firstVisibleColumnIndex, firstRowIndex/*, false, false*/);
  2511. Debug.Assert(success);
  2512. }
  2513. else
  2514. {
  2515. if (previousVisibleColumnIndex == -1)
  2516. {
  2517. return true;
  2518. }
  2519. if (!ScrollIntoView(previousVisibleColumnIndex, this.CurrentRowIndex, true))
  2520. {
  2521. return true;
  2522. }
  2523. if (IsRowOutOfBounds(this.CurrentRowIndex) || IsColumnOutOfBounds(previousVisibleColumnIndex))
  2524. {
  2525. return true;
  2526. }
  2527. success = SetCurrentCellCore(previousVisibleColumnIndex, this.CurrentRowIndex/*, false, false*/);
  2528. Debug.Assert(success);
  2529. }
  2530. }
  2531. }
  2532. finally
  2533. {
  2534. this.NoSelectionChangeCount--;
  2535. }
  2536. return true;
  2537. }
  2538. internal bool ProcessNextKey()
  2539. {
  2540. bool ctrl;
  2541. bool shift;
  2542. KeyboardHelper.GetMetaKeyState(out ctrl, out shift);
  2543. DataGridColumn dataGridColumn = this.ColumnsInternal.FirstVisibleColumn;
  2544. int firstVisibleColumnIndex = (dataGridColumn == null) ? -1 : dataGridColumn.Index;
  2545. if (firstVisibleColumnIndex == -1)
  2546. {
  2547. return false;
  2548. }
  2549. int nextScreenRowIndexTmp, nextScreenRowIndex = -1, jumpRows = 0;
  2550. if (this.CurrentRowIndex == -1)
  2551. {
  2552. nextScreenRowIndex = this.DisplayData.FirstDisplayedScrollingRow;
  2553. if (nextScreenRowIndex == -1)
  2554. {
  2555. return false;
  2556. }
  2557. }
  2558. else
  2559. {
  2560. nextScreenRowIndex = this.CurrentRowIndex;
  2561. }
  2562. jumpRows += this.DisplayData.NumTotallyDisplayedScrollingRows;
  2563. nextScreenRowIndexTmp = nextScreenRowIndex;
  2564. Debug.Assert(nextScreenRowIndexTmp != -1);
  2565. if (jumpRows == 0)
  2566. {
  2567. jumpRows = 1;
  2568. }
  2569. while (jumpRows > 0 && nextScreenRowIndexTmp != -1)
  2570. {
  2571. nextScreenRowIndexTmp = this.GetNextRow(nextScreenRowIndex);
  2572. if (nextScreenRowIndexTmp != -1)
  2573. {
  2574. nextScreenRowIndex = nextScreenRowIndexTmp;
  2575. jumpRows--;
  2576. }
  2577. }
  2578. this._noSelectionChangeCount++;
  2579. try
  2580. {
  2581. if (this.CurrentColumnIndex == -1)
  2582. {
  2583. Debug.Assert(_selectedItems.Count == 0);
  2584. SetRowSelection(nextScreenRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  2585. ScrollIntoView(firstVisibleColumnIndex, nextScreenRowIndex, false);
  2586. if (IsInnerCellOutOfBounds(firstVisibleColumnIndex, nextScreenRowIndex))
  2587. {
  2588. return true;
  2589. }
  2590. SetCurrentCellCore(firstVisibleColumnIndex, nextScreenRowIndex/*, false, false*/);
  2591. return true;
  2592. }
  2593. if (!PrepareForScroll(this.CurrentColumnIndex, nextScreenRowIndex, true))
  2594. {
  2595. return false;
  2596. }
  2597. if (shift && this.SelectionMode == DataGridSelectionMode.Extended)
  2598. {
  2599. ClearRowSelection(nextScreenRowIndex, false /*resetAnchorRowIndex*/);
  2600. if (this.AnchorRowIndex == -1)
  2601. {
  2602. return true;
  2603. }
  2604. if (this.AnchorRowIndex < nextScreenRowIndex)
  2605. {
  2606. SetRowsSelection(this.AnchorRowIndex, nextScreenRowIndex);
  2607. }
  2608. else
  2609. {
  2610. SetRowsSelection(nextScreenRowIndex, this.AnchorRowIndex);
  2611. }
  2612. }
  2613. else
  2614. {
  2615. ClearRowSelection(nextScreenRowIndex, true /*resetAnchorRowIndex*/);
  2616. }
  2617. // Scrolling needs to be done after Selection is updated
  2618. if (!ScrollIntoView(this.CurrentColumnIndex, nextScreenRowIndex, true))
  2619. {
  2620. return true;
  2621. }
  2622. if (this.CurrentColumnIndex == -1 || IsRowOutOfBounds(nextScreenRowIndex))
  2623. {
  2624. return true;
  2625. }
  2626. bool success = SetCurrentCellCore(this.CurrentColumnIndex, nextScreenRowIndex/*, false, false*/);
  2627. Debug.Assert(success);
  2628. return true;
  2629. }
  2630. finally
  2631. {
  2632. this.NoSelectionChangeCount--;
  2633. }
  2634. }
  2635. internal bool ProcessPriorKey()
  2636. {
  2637. bool ctrl;
  2638. bool shift;
  2639. bool success;
  2640. KeyboardHelper.GetMetaKeyState(out ctrl, out shift);
  2641. DataGridColumn dataGridColumn = this.ColumnsInternal.FirstVisibleColumn;
  2642. int firstVisibleColumnIndex = (dataGridColumn == null) ? -1 : dataGridColumn.Index;
  2643. if (firstVisibleColumnIndex == -1)
  2644. {
  2645. return false;
  2646. }
  2647. int previousScreenRowIndexTmp, previousScreenRowIndex = -1;
  2648. if (this.CurrentRowIndex == -1)
  2649. {
  2650. previousScreenRowIndex = this.DisplayData.FirstDisplayedScrollingRow;
  2651. if (previousScreenRowIndex == -1)
  2652. {
  2653. return false;
  2654. }
  2655. }
  2656. else
  2657. {
  2658. previousScreenRowIndex = this.CurrentRowIndex;
  2659. }
  2660. int jumpRows = this.DisplayData.NumTotallyDisplayedScrollingRows;
  2661. if (jumpRows == 0)
  2662. {
  2663. jumpRows = 1;
  2664. }
  2665. previousScreenRowIndexTmp = previousScreenRowIndex;
  2666. Debug.Assert(previousScreenRowIndexTmp != -1);
  2667. while (jumpRows > 0 && previousScreenRowIndexTmp != -1)
  2668. {
  2669. previousScreenRowIndexTmp = GetPreviousRow(previousScreenRowIndex);
  2670. if (previousScreenRowIndexTmp != -1)
  2671. {
  2672. previousScreenRowIndex = previousScreenRowIndexTmp;
  2673. }
  2674. jumpRows--;
  2675. }
  2676. Debug.Assert(previousScreenRowIndex != -1);
  2677. this._noSelectionChangeCount++;
  2678. try
  2679. {
  2680. if (this.CurrentColumnIndex == -1)
  2681. {
  2682. Debug.Assert(_selectedItems.Count == 0);
  2683. SetRowSelection(previousScreenRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  2684. success = ScrollIntoView(firstVisibleColumnIndex, previousScreenRowIndex, false);
  2685. Debug.Assert(success);
  2686. if (IsInnerCellOutOfBounds(firstVisibleColumnIndex, previousScreenRowIndex))
  2687. {
  2688. return true;
  2689. }
  2690. success = SetCurrentCellCore(firstVisibleColumnIndex, previousScreenRowIndex/*, false, false*/);
  2691. //
  2692. return true;
  2693. }
  2694. if (!ScrollIntoView(this.CurrentColumnIndex, previousScreenRowIndex, true))
  2695. {
  2696. return true;
  2697. }
  2698. if (this.CurrentColumnIndex == -1 || IsRowOutOfBounds(previousScreenRowIndex))
  2699. {
  2700. return true;
  2701. }
  2702. if (shift && this.SelectionMode == DataGridSelectionMode.Extended)
  2703. {
  2704. ClearRowSelection(previousScreenRowIndex, false /*resetAnchorRowIndex*/);
  2705. if (this.AnchorRowIndex == -1)
  2706. {
  2707. return true;
  2708. }
  2709. if (this.AnchorRowIndex < previousScreenRowIndex)
  2710. {
  2711. SetRowsSelection(this.AnchorRowIndex, previousScreenRowIndex);
  2712. }
  2713. else
  2714. {
  2715. SetRowsSelection(previousScreenRowIndex, this.AnchorRowIndex);
  2716. }
  2717. }
  2718. else
  2719. {
  2720. ClearRowSelection(previousScreenRowIndex, true /*resetAnchorRowIndex*/);
  2721. }
  2722. success = SetCurrentCellCore(this.CurrentColumnIndex, previousScreenRowIndex/*, false, false*/);
  2723. Debug.Assert(success);
  2724. }
  2725. finally
  2726. {
  2727. this.NoSelectionChangeCount--;
  2728. }
  2729. return true;
  2730. }
  2731. internal bool ProcessRightKey()
  2732. {
  2733. bool success;
  2734. bool ctrl;
  2735. bool shift;
  2736. KeyboardHelper.GetMetaKeyState(out ctrl, out shift);
  2737. DataGridColumn dataGridColumn = this.ColumnsInternal.LastVisibleColumn;
  2738. int lastVisibleColumnIndex = (dataGridColumn == null) ? -1 : dataGridColumn.Index;
  2739. int firstRowIndex = this.FirstRowIndex;
  2740. if (lastVisibleColumnIndex == -1 || firstRowIndex == -1)
  2741. {
  2742. return false;
  2743. }
  2744. int nextVisibleColumnIndex = -1;
  2745. if (this.CurrentColumnIndex != -1)
  2746. {
  2747. dataGridColumn = this.ColumnsInternal.GetNextVisibleColumn(this.Columns[this.CurrentColumnIndex]);
  2748. if (dataGridColumn != null)
  2749. {
  2750. nextVisibleColumnIndex = dataGridColumn.Index;
  2751. }
  2752. }
  2753. this._noSelectionChangeCount++;
  2754. try
  2755. {
  2756. if (ctrl)
  2757. {
  2758. return ProcessRightMost(lastVisibleColumnIndex, firstRowIndex);
  2759. }
  2760. else
  2761. {
  2762. if (this.CurrentColumnIndex == -1)
  2763. {
  2764. Debug.Assert(_selectedItems.Count == 0);
  2765. SetRowSelection(firstRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  2766. success = ScrollIntoView(lastVisibleColumnIndex, firstRowIndex, false);
  2767. Debug.Assert(success);
  2768. if (IsInnerCellOutOfBounds(lastVisibleColumnIndex, firstRowIndex))
  2769. {
  2770. return true;
  2771. }
  2772. success = SetCurrentCellCore(lastVisibleColumnIndex, firstRowIndex/*, false, false*/);
  2773. Debug.Assert(success);
  2774. }
  2775. else
  2776. {
  2777. if (nextVisibleColumnIndex == -1)
  2778. {
  2779. return true;
  2780. }
  2781. if (!ScrollIntoView(nextVisibleColumnIndex, this.CurrentRowIndex, true))
  2782. {
  2783. return true;
  2784. }
  2785. if (IsRowOutOfBounds(this.CurrentRowIndex) || IsColumnOutOfBounds(nextVisibleColumnIndex))
  2786. {
  2787. return true;
  2788. }
  2789. success = SetCurrentCellCore(nextVisibleColumnIndex, this.CurrentRowIndex/*, false, false*/);
  2790. Debug.Assert(success);
  2791. }
  2792. }
  2793. }
  2794. finally
  2795. {
  2796. this.NoSelectionChangeCount--;
  2797. }
  2798. return true;
  2799. }
  2800. [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  2801. internal bool ProcessUpKey()
  2802. {
  2803. bool ctrl;
  2804. bool shift;
  2805. bool success;
  2806. KeyboardHelper.GetMetaKeyState(out ctrl, out shift);
  2807. DataGridColumn dataGridColumn = this.ColumnsInternal.FirstVisibleColumn;
  2808. int firstVisibleColumnIndex = (dataGridColumn == null) ? -1 : dataGridColumn.Index;
  2809. int firstRowIndex = this.FirstRowIndex;
  2810. if (firstVisibleColumnIndex == -1 || firstRowIndex == -1)
  2811. {
  2812. return false;
  2813. }
  2814. int previousRowIndex = -1;
  2815. if (this.CurrentRowIndex != -1)
  2816. {
  2817. previousRowIndex = GetPreviousRow(this.CurrentRowIndex);
  2818. //
  2819. }
  2820. //
  2821. this._noSelectionChangeCount++;
  2822. try
  2823. {
  2824. if (ctrl)
  2825. {
  2826. if (shift)
  2827. {
  2828. if (this.CurrentColumnIndex == -1)
  2829. {
  2830. Debug.Assert(_selectedItems.Count == 0);
  2831. SetRowSelection(firstRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  2832. success = ScrollIntoView(firstVisibleColumnIndex, firstRowIndex, false);
  2833. Debug.Assert(success);
  2834. if (IsInnerCellOutOfBounds(firstVisibleColumnIndex, firstRowIndex))
  2835. {
  2836. return true;
  2837. }
  2838. success = SetCurrentCellCore(firstVisibleColumnIndex, firstRowIndex/*, false, false*/);
  2839. Debug.Assert(success);
  2840. }
  2841. else
  2842. {
  2843. if (this.SelectionMode == DataGridSelectionMode.Extended)
  2844. {
  2845. if (!ScrollIntoView(this.CurrentColumnIndex, firstRowIndex, true))
  2846. {
  2847. return true;
  2848. }
  2849. if (/*this.ptAnchorCell.X == -1 ||*/ this.CurrentColumnIndex == -1 ||
  2850. IsRowOutOfBounds(firstRowIndex))
  2851. {
  2852. return true;
  2853. }
  2854. ClearRowSelection(firstRowIndex, false /*resetAnchorRowIndex*/);
  2855. Debug.Assert(this.AnchorRowIndex >= 0);
  2856. SetRowsSelection(firstRowIndex, this.AnchorRowIndex);
  2857. success = SetCurrentCellCore(this.CurrentColumnIndex, firstRowIndex/*, false, false*/);
  2858. Debug.Assert(success);
  2859. }
  2860. else
  2861. {
  2862. if (!ScrollIntoView(this.CurrentColumnIndex, firstRowIndex, true))
  2863. {
  2864. return true;
  2865. }
  2866. if (this.CurrentColumnIndex == -1 || IsRowOutOfBounds(firstRowIndex))
  2867. {
  2868. return true;
  2869. }
  2870. if (firstRowIndex != this.SelectedIndex)
  2871. {
  2872. SetRowSelection(this.CurrentRowIndex, false /*isSelected*/, false /*setAnchorRowIndex*/);
  2873. SetRowSelection(firstRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  2874. }
  2875. success = SetCurrentCellCore(this.CurrentColumnIndex, firstRowIndex/*, false, false*/);
  2876. Debug.Assert(success);
  2877. }
  2878. }
  2879. }
  2880. else
  2881. {
  2882. if (this.CurrentColumnIndex == -1)
  2883. {
  2884. Debug.Assert(_selectedItems.Count == 0);
  2885. SetRowSelection(firstRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  2886. success = ScrollIntoView(firstVisibleColumnIndex, firstRowIndex, false);
  2887. Debug.Assert(success);
  2888. if (IsInnerCellOutOfBounds(firstVisibleColumnIndex, firstRowIndex))
  2889. {
  2890. return true;
  2891. }
  2892. success = SetCurrentCellCore(firstVisibleColumnIndex, firstRowIndex/*, false, false*/);
  2893. //
  2894. }
  2895. else
  2896. {
  2897. if (!ScrollIntoView(this.CurrentColumnIndex, firstRowIndex, true))
  2898. {
  2899. return true;
  2900. }
  2901. if (this.CurrentColumnIndex == -1 || IsRowOutOfBounds(firstRowIndex))
  2902. {
  2903. return true;
  2904. }
  2905. ClearRowSelection(firstRowIndex, true /*resetAnchorRowIndex*/);
  2906. success = SetCurrentCellCore(this.CurrentColumnIndex, firstRowIndex/*, false, false*/);
  2907. Debug.Assert(success);
  2908. }
  2909. }
  2910. }
  2911. else
  2912. {
  2913. if (shift)
  2914. {
  2915. if (this.CurrentColumnIndex == -1)
  2916. {
  2917. Debug.Assert(_selectedItems.Count == 0);
  2918. SetRowSelection(firstRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  2919. success = ScrollIntoView(firstVisibleColumnIndex, firstRowIndex, false);
  2920. Debug.Assert(success);
  2921. if (IsInnerCellOutOfBounds(firstVisibleColumnIndex, firstRowIndex))
  2922. {
  2923. return true;
  2924. }
  2925. success = SetCurrentCellCore(firstVisibleColumnIndex, firstRowIndex/*, false, false*/);
  2926. Debug.Assert(success);
  2927. }
  2928. else
  2929. {
  2930. if (previousRowIndex == -1)
  2931. {
  2932. return true;
  2933. }
  2934. if (!ScrollIntoView(this.CurrentColumnIndex, previousRowIndex, true))
  2935. {
  2936. return true;
  2937. }
  2938. if (this.CurrentColumnIndex == -1 || IsRowOutOfBounds(previousRowIndex))
  2939. {
  2940. return true;
  2941. }
  2942. ClearRowSelection(false /*resetAnchorRowIndex*/);
  2943. if (this.SelectionMode == DataGridSelectionMode.Extended)
  2944. {
  2945. if (this.AnchorRowIndex == -1)
  2946. {
  2947. return true;
  2948. }
  2949. if (this.AnchorRowIndex >= previousRowIndex)
  2950. {
  2951. SetRowsSelection(previousRowIndex, this.AnchorRowIndex);
  2952. }
  2953. else
  2954. {
  2955. SetRowsSelection(this.AnchorRowIndex, previousRowIndex);
  2956. }
  2957. }
  2958. else
  2959. {
  2960. SetRowSelection(previousRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  2961. }
  2962. success = this.SetCurrentCellCore(this.CurrentColumnIndex, previousRowIndex/*, false, false*/);
  2963. Debug.Assert(success);
  2964. }
  2965. }
  2966. else
  2967. {
  2968. if (this.CurrentColumnIndex == -1)
  2969. {
  2970. Debug.Assert(_selectedItems.Count == 0);
  2971. SetRowSelection(firstRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  2972. success = ScrollIntoView(firstVisibleColumnIndex, firstRowIndex, false);
  2973. Debug.Assert(success);
  2974. if (IsInnerCellOutOfBounds(firstVisibleColumnIndex, firstRowIndex))
  2975. {
  2976. return true;
  2977. }
  2978. success = SetCurrentCellCore(firstVisibleColumnIndex, firstRowIndex/*, false, false*/);
  2979. //
  2980. }
  2981. else
  2982. {
  2983. //
  2984. if (previousRowIndex == -1)
  2985. {
  2986. return true;
  2987. }
  2988. //
  2989. if (previousRowIndex != -1)
  2990. {
  2991. if (!ScrollIntoView(this.CurrentColumnIndex, previousRowIndex, true))
  2992. {
  2993. return true;
  2994. }
  2995. }
  2996. if (this.CurrentColumnIndex == -1 || IsRowOutOfBounds(previousRowIndex))
  2997. {
  2998. return true;
  2999. }
  3000. ClearRowSelection(previousRowIndex, true /*resetAnchorRowIndex*/);
  3001. success = SetCurrentCellCore(this.CurrentColumnIndex, previousRowIndex/*, false, false*/);
  3002. Debug.Assert(success);
  3003. }
  3004. }
  3005. }
  3006. }
  3007. finally
  3008. {
  3009. this.NoSelectionChangeCount--;
  3010. }
  3011. return true;
  3012. }
  3013. internal void ProcessVerticalScroll(ScrollEventType scrollEventType)
  3014. {
  3015. if (this._verticalScrollChangesIgnored > 0)
  3016. {
  3017. return;
  3018. }
  3019. //
  3020. Debug.Assert(DoubleUtil.LessThanOrClose(this._vScrollBar.Value, this._vScrollBar.Maximum));
  3021. this._verticalScrollChangesIgnored++;
  3022. try
  3023. {
  3024. Debug.Assert(this._vScrollBar != null);
  3025. if (scrollEventType == ScrollEventType.SmallIncrement)
  3026. {
  3027. this.DisplayData.PendingVerticalScrollHeight = GetVerticalSmallScrollIncrease();
  3028. double newVerticalOffset = this._verticalOffset + this.DisplayData.PendingVerticalScrollHeight;
  3029. if (newVerticalOffset > this._vScrollBar.Maximum)
  3030. {
  3031. this.DisplayData.PendingVerticalScrollHeight -= newVerticalOffset - this._vScrollBar.Maximum;
  3032. }
  3033. }
  3034. else if (scrollEventType == ScrollEventType.SmallDecrement)
  3035. {
  3036. if (DoubleUtil.GreaterThan(this.NegVerticalOffset, 0))
  3037. {
  3038. this.DisplayData.PendingVerticalScrollHeight -= this.NegVerticalOffset;
  3039. }
  3040. else
  3041. {
  3042. if (this.DisplayData.FirstDisplayedScrollingRow > 0)
  3043. {
  3044. ScrollRowIntoView(this.DisplayData.FirstDisplayedScrollingRow - 1);
  3045. }
  3046. return;
  3047. }
  3048. }
  3049. else
  3050. {
  3051. this.DisplayData.PendingVerticalScrollHeight = this._vScrollBar.Value - this._verticalOffset;
  3052. }
  3053. if (!DoubleUtil.IsZero(this.DisplayData.PendingVerticalScrollHeight))
  3054. {
  3055. // Invalidate so the scroll happens on idle
  3056. InvalidateRowsMeasure(false /*invalidateIndividualRows*/);
  3057. }
  3058. //
  3059. }
  3060. finally
  3061. {
  3062. this._verticalScrollChangesIgnored--;
  3063. }
  3064. }
  3065. internal void RefreshRowsAndColumns()
  3066. {
  3067. ClearRows(false);
  3068. if (this.AutoGenerateColumns)
  3069. {
  3070. //Column auto-generation refreshes the rows too
  3071. AutoGenerateColumnsPrivate();
  3072. }
  3073. foreach (DataGridColumn column in this.ColumnsItemsInternal)
  3074. {
  3075. //We don't need to refresh the state of AutoGenerated column headers because they're up-to-date
  3076. if (!column.IsAutoGenerated && column.HasHeaderCell)
  3077. {
  3078. column.HeaderCell.ApplyState();
  3079. }
  3080. }
  3081. RefreshRows(false);
  3082. if (this.Columns.Count > 0 && this.CurrentColumnIndex == -1)
  3083. {
  3084. MakeFirstDisplayedCellCurrentCell();
  3085. }
  3086. }
  3087. //
  3088. internal bool ScrollIntoView(int columnIndex, int rowIndex, bool forCurrentCellChange)
  3089. {
  3090. Debug.Assert(columnIndex >= 0 && columnIndex < this.Columns.Count);
  3091. Debug.Assert(this.DisplayData.FirstDisplayedScrollingCol >= -1 && this.DisplayData.FirstDisplayedScrollingCol < this.Columns.Count);
  3092. Debug.Assert(this.DisplayData.LastTotallyDisplayedScrollingCol >= -1 && this.DisplayData.LastTotallyDisplayedScrollingCol < this.Columns.Count);
  3093. Debug.Assert(!IsRowOutOfBounds(rowIndex));
  3094. Debug.Assert(this.DisplayData.FirstDisplayedScrollingRow >= -1 && this.DisplayData.FirstDisplayedScrollingRow < this.RowCount);
  3095. Debug.Assert(this.Columns[columnIndex].Visibility == Visibility.Visible);
  3096. if (!PrepareForScroll(columnIndex, rowIndex, forCurrentCellChange))
  3097. {
  3098. return false;
  3099. }
  3100. //scroll horizontally
  3101. if (!ScrollColumnIntoView(columnIndex))
  3102. {
  3103. return false;
  3104. }
  3105. if (IsInnerCellOutOfBounds(columnIndex, rowIndex))
  3106. {
  3107. return false;
  3108. }
  3109. //scroll vertically
  3110. if (!ScrollRowIntoView(rowIndex))
  3111. {
  3112. return false;
  3113. }
  3114. DataGridAutomationPeer peer = DataGridAutomationPeer.FromElement(this) as DataGridAutomationPeer;
  3115. if (peer != null)
  3116. {
  3117. peer.RaiseAutomationScrollEvents();
  3118. }
  3119. return true;
  3120. }
  3121. // Convenient overload that commits the current edit.
  3122. internal bool SetCurrentCellCore(int columnIndex, int rowIndex)
  3123. {
  3124. return SetCurrentCellCore(columnIndex, rowIndex, true /*commitEdit*/);
  3125. }
  3126. internal void UpdateHorizontalOffset(double newValue)
  3127. {
  3128. if (this.HorizontalOffset != newValue)
  3129. {
  3130. this.HorizontalOffset = newValue;
  3131. InvalidateColumnHeadersMeasure();
  3132. InvalidateRowsMeasure(true);
  3133. }
  3134. }
  3135. [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  3136. internal bool UpdateStateOnMouseLeftButtonDown(MouseButtonEventArgs mouseButtonEventArgs, int columnIndex, int rowIndex)
  3137. {
  3138. bool ctrl, shift, beginEdit;
  3139. KeyboardHelper.GetMetaKeyState(out ctrl, out shift);
  3140. Debug.Assert(rowIndex >= 0);
  3141. // Before changing selection, check if the current cell needs to be committed, and
  3142. // check if the current row needs to be committed. If any of those two operations are required and fail,
  3143. // do no change selection, and do not change current cell.
  3144. bool wasInEdit = this.EditingColumnIndex != -1;
  3145. if (this.CurrentRowIndex != rowIndex && !CommitEdit(DataGridEditingUnit.Row, true /*exitEditing*/))
  3146. {
  3147. // Edited value couldn't be committed or aborted
  3148. return true;
  3149. }
  3150. if (IsRowOutOfBounds(rowIndex))
  3151. {
  3152. return true;
  3153. }
  3154. try
  3155. {
  3156. this._noSelectionChangeCount++;
  3157. if (this.SelectionMode == DataGridSelectionMode.Extended && shift && this.AnchorRowIndex != -1)
  3158. {
  3159. // Shift select multiple rows
  3160. int anchorRowIndex = this.AnchorRowIndex;
  3161. ClearRowSelection(rowIndex /*rowIndexException*/, false /*resetAnchorRowIndex*/);
  3162. if (rowIndex <= anchorRowIndex)
  3163. {
  3164. SetRowsSelection(rowIndex, anchorRowIndex);
  3165. }
  3166. else
  3167. {
  3168. SetRowsSelection(anchorRowIndex, rowIndex);
  3169. }
  3170. }
  3171. else if (GetRowSelection(rowIndex)) // Unselecting single row or Selecting a previously multi-selected row
  3172. {
  3173. if (!ctrl && this.SelectionMode == DataGridSelectionMode.Extended && _selectedItems.Count != 0)
  3174. {
  3175. // Unselect everything except the row that was clicked on
  3176. ClearRowSelection(rowIndex /*rowIndexException*/, true /*setAnchorRowIndex*/);
  3177. }
  3178. else if (ctrl)
  3179. {
  3180. if (!CommitEdit(DataGridEditingUnit.Row, true /*exitEditing*/))
  3181. {
  3182. // Edited value couldn't be committed or aborted
  3183. return true;
  3184. }
  3185. SetRowSelection(rowIndex, false /*isSelected*/, false /*setAnchorRowIndex*/);
  3186. }
  3187. }
  3188. else // Selecting a single row or multi-selecting with Ctrl
  3189. {
  3190. if (this.SelectionMode == DataGridSelectionMode.Single || !ctrl)
  3191. {
  3192. // Unselect the currectly selected rows except the new selected row
  3193. ClearRowSelection(rowIndex /*rowIndexException*/, true /*setAnchorRowIndex*/);
  3194. }
  3195. else
  3196. {
  3197. SetRowSelection(rowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  3198. }
  3199. }
  3200. if (IsRowOutOfBounds(rowIndex) || (columnIndex != -1 && IsColumnOutOfBounds(columnIndex)))
  3201. {
  3202. return true;
  3203. }
  3204. beginEdit = this.CurrentRowIndex == rowIndex &&
  3205. columnIndex != -1 &&
  3206. (wasInEdit || this.CurrentColumnIndex == columnIndex) &&
  3207. !GetColumnEffectiveReadOnlyState(this.Columns[columnIndex]);
  3208. if (this.CurrentRowIndex != rowIndex ||
  3209. (this.CurrentColumnIndex != columnIndex && columnIndex != -1))
  3210. {
  3211. if (columnIndex == -1)
  3212. {
  3213. if (this.CurrentColumnIndex != -1)
  3214. {
  3215. columnIndex = this.CurrentColumnIndex;
  3216. }
  3217. else
  3218. {
  3219. DataGridColumn firstVisibleColumn = this.ColumnsInternal.FirstVisibleColumn;
  3220. if (firstVisibleColumn != null)
  3221. {
  3222. columnIndex = firstVisibleColumn.Index;
  3223. }
  3224. }
  3225. }
  3226. if (columnIndex != -1)
  3227. {
  3228. bool success = SetCurrentCellCore(columnIndex, rowIndex);
  3229. Debug.Assert(success);
  3230. success = ScrollRowIntoView(rowIndex);
  3231. Debug.Assert(success);
  3232. }
  3233. }
  3234. }
  3235. finally
  3236. {
  3237. this.NoSelectionChangeCount--;
  3238. }
  3239. if (beginEdit && BeginCellEdit(mouseButtonEventArgs))
  3240. {
  3241. FocusEditingCell(true /*setFocus*/);
  3242. }
  3243. return true;
  3244. }
  3245. internal void UpdateVerticalScrollBar()
  3246. {
  3247. if (this._vScrollBar != null && this._vScrollBar.Visibility == Visibility.Visible)
  3248. {
  3249. UpdateVerticalScrollBar(true /*needVertScrollbar*/, false /*forceVertScrollbar*/, this.EdgedRowsHeightCalculated, this.CellsHeight);
  3250. }
  3251. }
  3252. #endregion Internal Methods
  3253. #region Private Methods
  3254. private void AddNewCellPrivate(DataGridRow row, DataGridColumn column)
  3255. {
  3256. DataGridCell newCell = new DataGridCell();
  3257. PopulateCellContent(true /*forceTemplating*/, false /*isCellEdited*/, column, row, newCell);
  3258. if (row.OwningGrid != null)
  3259. {
  3260. newCell.OwningColumn = column;
  3261. newCell.Visibility = column.Visibility;
  3262. }
  3263. newCell.EnsureCellStyle();
  3264. row.Cells.Insert(column.Index, newCell);
  3265. }
  3266. //
  3267. private bool BeginCellEdit(RoutedEventArgs editingEventArgs)
  3268. {
  3269. //
  3270. if (this.CurrentColumnIndex == -1 || !GetRowSelection(this.CurrentRowIndex))
  3271. {
  3272. //
  3273. return false;
  3274. }
  3275. Debug.Assert(this.CurrentColumnIndex >= 0);
  3276. Debug.Assert(this.CurrentColumnIndex < this.Columns.Count);
  3277. Debug.Assert(this.CurrentRowIndex >= -1);
  3278. Debug.Assert(this.CurrentRowIndex < this.RowCount);
  3279. Debug.Assert(this._editingRow == null || this.EditingRowIndex == this.CurrentRowIndex);
  3280. Debug.Assert(!GetColumnEffectiveReadOnlyState(this.CurrentColumn));
  3281. Debug.Assert(this.CurrentColumn.Visibility == Visibility.Visible);
  3282. if (this._editingColumnIndex != -1)
  3283. {
  3284. // Current cell is already in edit mode
  3285. Debug.Assert(this._editingColumnIndex == this.CurrentColumnIndex);
  3286. //
  3287. return true;
  3288. }
  3289. DataGridRow dataGridRow = this._editingRow;
  3290. if (dataGridRow == null)
  3291. {
  3292. if (this.DisplayData.IsRowDisplayed(this.CurrentRowIndex))
  3293. {
  3294. dataGridRow = this.DisplayData.GetDisplayedRow(this.CurrentRowIndex);
  3295. }
  3296. else
  3297. {
  3298. dataGridRow = GenerateRow(this.CurrentRowIndex);
  3299. }
  3300. }
  3301. Debug.Assert(dataGridRow != null);
  3302. DataGridCell dataGridCell = dataGridRow.Cells[this.CurrentColumnIndex];
  3303. DataGridBeginningEditEventArgs e = new DataGridBeginningEditEventArgs(this.CurrentColumn, dataGridRow, editingEventArgs);
  3304. OnBeginningEdit(e);
  3305. if (e.Cancel)
  3306. {
  3307. //
  3308. return false;
  3309. }
  3310. if (this._editingRow == null && !BeginRowEdit(dataGridRow))
  3311. {
  3312. //
  3313. return false;
  3314. }
  3315. Debug.Assert(this._editingRow != null);
  3316. Debug.Assert(this.EditingRowIndex == this.CurrentRowIndex);
  3317. this._editingColumnIndex = this.CurrentColumnIndex;
  3318. this._editingEventArgs = editingEventArgs;
  3319. this._editingRow.Cells[this.CurrentColumnIndex].ApplyCellState(true /*animate*/);
  3320. PopulateCellContent(false /*forceTemplating*/, true /*isCellEdited*/, this.CurrentColumn, dataGridRow, dataGridCell);
  3321. //
  3322. return true;
  3323. }
  3324. private bool BeginRowEdit(DataGridRow dataGridRow)
  3325. {
  3326. //
  3327. Debug.Assert(this._editingRow == null);
  3328. Debug.Assert(dataGridRow != null);
  3329. Debug.Assert(this.CurrentRowIndex >= -1);
  3330. Debug.Assert(this.CurrentRowIndex < this.RowCount);
  3331. if (this.DataConnection.BeginEdit(dataGridRow.DataContext))
  3332. {
  3333. this._editingRow = dataGridRow;
  3334. this._editingRow.ApplyState(true /*animate*/);
  3335. //
  3336. return true;
  3337. }
  3338. //
  3339. return false;
  3340. }
  3341. private void CancelCellEdit(bool exitEditingMode)
  3342. {
  3343. if (this._editingColumnIndex == -1)
  3344. {
  3345. return;
  3346. }
  3347. Debug.Assert(this._editingColumnIndex >= 0);
  3348. Debug.Assert(this._editingColumnIndex < this.ColumnsItemsInternal.Count);
  3349. Debug.Assert(this._editingRow != null);
  3350. Debug.Assert(this.CurrentColumn != null);
  3351. //
  3352. // Write the old cell value back into the cell content.
  3353. DataGridCell editingCell = this._editingRow.Cells[this._editingColumnIndex];
  3354. Debug.Assert(editingCell != null);
  3355. FrameworkElement editingElement = editingCell.Content as FrameworkElement;
  3356. DataGridTemplateColumn templateColumn = this.CurrentColumn as DataGridTemplateColumn;
  3357. if (templateColumn != null)
  3358. {
  3359. PopulateCellContent(true /*forceTemplating*/, !exitEditingMode /*isCellEdited*/, templateColumn, this._editingRow, editingCell);
  3360. }
  3361. else
  3362. {
  3363. this.CurrentColumn.CancelCellEditInternal(editingElement, this._uneditedValue);
  3364. }
  3365. }
  3366. private void CancelRowEdit(bool exitEditingMode)
  3367. {
  3368. if (this._editingRow == null)
  3369. {
  3370. return;
  3371. }
  3372. Debug.Assert(this.EditingRowIndex >= -1);
  3373. Debug.Assert(this.EditingRowIndex < this.RowCount);
  3374. Debug.Assert(this.CurrentColumn != null);
  3375. object dataItem = this._editingRow.DataContext;
  3376. if (!this.DataConnection.CancelEdit(dataItem))
  3377. {
  3378. return;
  3379. }
  3380. //
  3381. foreach (DataGridColumn column in this.Columns)
  3382. {
  3383. if (!exitEditingMode && column.Index == this._editingColumnIndex && column is DataGridBoundColumn)
  3384. {
  3385. continue;
  3386. }
  3387. PopulateCellContent(true /*forceTemplating*/, !exitEditingMode && column.Index == this._editingColumnIndex /*isCellEdited*/, column, this._editingRow, this._editingRow.Cells[column.Index]);
  3388. }
  3389. }
  3390. private bool CommitEditForOperation(int columnIndex, int rowIndex, bool forCurrentCellChange)
  3391. {
  3392. if (forCurrentCellChange)
  3393. {
  3394. if (!EndCellEdit(true /*commitCellEdit*/, true /*exitEditingMode*/, true /*keepFocus*/))
  3395. {
  3396. return false;
  3397. }
  3398. if (this.CurrentRowIndex != rowIndex &&
  3399. !EndRowEdit(true /*commitRowEdit*/, true /*exitEditingMode*/))
  3400. {
  3401. return false;
  3402. }
  3403. }
  3404. //
  3405. if (IsColumnOutOfBounds(columnIndex))
  3406. {
  3407. return false;
  3408. }
  3409. if (rowIndex >= this.RowCount)
  3410. {
  3411. // Current cell was reset because the commit deleted row(s).
  3412. // Since the user wants to change the current cell, we don't
  3413. // want to end up with no current cell. We pick the last row
  3414. // in the grid which may be the 'new row'.
  3415. int lastRowIndex = this.LastRowIndex;
  3416. if (forCurrentCellChange &&
  3417. this.CurrentColumnIndex == -1 &&
  3418. lastRowIndex != -1)
  3419. {
  3420. bool success = SetAndSelectCurrentCell(columnIndex,
  3421. lastRowIndex,
  3422. false /*forceCurrentCellSelection (unused here)*/);
  3423. Debug.Assert(success);
  3424. }
  3425. // Interrupt operation because it has become invalid.
  3426. return false;
  3427. }
  3428. return true;
  3429. }
  3430. [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
  3431. private void CommitRowEdit(bool exitEditingMode)
  3432. {
  3433. if (this._editingRow == null)
  3434. {
  3435. return;
  3436. }
  3437. Debug.Assert(this.EditingRowIndex >= -1);
  3438. Debug.Assert(this.EditingRowIndex < this.RowCount);
  3439. //
  3440. this.DataConnection.EndEdit(this._editingRow.DataContext);
  3441. if (!exitEditingMode)
  3442. {
  3443. this.DataConnection.BeginEdit(this._editingRow.DataContext);
  3444. }
  3445. this.DataConnection.EndEdit(this._editingRow.DataContext);
  3446. }
  3447. private void CompleteCellsCollection(DataGridRow dataGridRow)
  3448. {
  3449. Debug.Assert(dataGridRow != null);
  3450. int cellsInCollection = dataGridRow.Cells.Count;
  3451. if (this.ColumnsItemsInternal.Count > cellsInCollection)
  3452. {
  3453. for (int columnIndex = cellsInCollection; columnIndex < this.ColumnsItemsInternal.Count; columnIndex++)
  3454. {
  3455. AddNewCellPrivate(dataGridRow, this.ColumnsItemsInternal[columnIndex]);
  3456. }
  3457. }
  3458. }
  3459. [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  3460. private void ComputeScrollBarsLayout()
  3461. {
  3462. if (this._ignoreNextScrollBarsLayout)
  3463. {
  3464. this._ignoreNextScrollBarsLayout = false;
  3465. //
  3466. }
  3467. double cellsWidth = this.CellsWidth;
  3468. double cellsHeight = this.CellsHeight;
  3469. bool allowHorizScrollbar = false;
  3470. bool forceHorizScrollbar = false;
  3471. double horizScrollBarHeight = 0;
  3472. if (_hScrollBar != null)
  3473. {
  3474. forceHorizScrollbar = this.HorizontalScrollBarVisibility == ScrollBarVisibility.Visible;
  3475. allowHorizScrollbar = forceHorizScrollbar || (this.ColumnsInternal.VisibleColumnCount > 0 &&
  3476. this.HorizontalScrollBarVisibility != ScrollBarVisibility.Disabled &&
  3477. this.HorizontalScrollBarVisibility != ScrollBarVisibility.Hidden);
  3478. // Compensate if the horizontal scrollbar is already taking up space
  3479. if (_hScrollBar.Visibility == Visibility.Visible)
  3480. {
  3481. cellsHeight += this._hScrollBar.DesiredSize.Height;
  3482. }
  3483. horizScrollBarHeight = _hScrollBar.Height;
  3484. }
  3485. bool allowVertScrollbar = false;
  3486. bool forceVertScrollbar = false;
  3487. double vertScrollBarWidth = 0;
  3488. if (_vScrollBar != null)
  3489. {
  3490. forceVertScrollbar = this.VerticalScrollBarVisibility == ScrollBarVisibility.Visible;
  3491. allowVertScrollbar = forceVertScrollbar || (this.ColumnsItemsInternal.Count > 0 &&
  3492. this.VerticalScrollBarVisibility != ScrollBarVisibility.Disabled &&
  3493. this.VerticalScrollBarVisibility != ScrollBarVisibility.Hidden);
  3494. // Compensate if the vertical scrollbar is already taking up space
  3495. if (_vScrollBar.Visibility == Visibility.Visible)
  3496. {
  3497. cellsWidth += _vScrollBar.DesiredSize.Width;
  3498. }
  3499. vertScrollBarWidth = _vScrollBar.Width;
  3500. }
  3501. // Now cellsWidth is the width potentially available for displaying data cells.
  3502. // Now cellsHeight is the height potentially available for displaying data cells.
  3503. bool needHorizScrollbar = false;
  3504. bool needVertScrollbar = false;
  3505. double totalVisibleWidth = this.ColumnsInternal.VisibleEdgedColumnsWidth;
  3506. double totalVisibleFrozenWidth = this.ColumnsInternal.GetVisibleFrozenEdgedColumnsWidth();
  3507. UpdateDisplayedRows(this.DisplayData.FirstDisplayedScrollingRow, this.CellsHeight);
  3508. double totalVisibleHeight = this.EdgedRowsHeightCalculated;
  3509. if (!forceHorizScrollbar && !forceVertScrollbar)
  3510. {
  3511. bool needHorizScrollbarWithoutVertScrollbar = false;
  3512. if (allowHorizScrollbar &&
  3513. DoubleUtil.GreaterThan(totalVisibleWidth, cellsWidth) &&
  3514. DoubleUtil.LessThan(totalVisibleFrozenWidth, cellsWidth) &&
  3515. DoubleUtil.LessThanOrClose(horizScrollBarHeight, cellsHeight))
  3516. {
  3517. double oldDataHeight = cellsHeight;
  3518. cellsHeight -= horizScrollBarHeight;
  3519. Debug.Assert(cellsHeight >= 0);
  3520. needHorizScrollbarWithoutVertScrollbar = needHorizScrollbar = true;
  3521. if (allowVertScrollbar && (DoubleUtil.LessThanOrClose(totalVisibleWidth - cellsWidth, vertScrollBarWidth) ||
  3522. DoubleUtil.LessThanOrClose(cellsWidth - totalVisibleFrozenWidth, vertScrollBarWidth)))
  3523. {
  3524. // Would we still need a horizontal scrollbar without the vertical one?
  3525. UpdateDisplayedRows(this.DisplayData.FirstDisplayedScrollingRow, cellsHeight);
  3526. if (this.DisplayData.NumTotallyDisplayedScrollingRows != this.RowCount)
  3527. {
  3528. needHorizScrollbar = DoubleUtil.LessThan(totalVisibleFrozenWidth, cellsWidth - vertScrollBarWidth);
  3529. }
  3530. }
  3531. if (!needHorizScrollbar)
  3532. {
  3533. // Restore old data height because turns out a horizontal scroll bar wouldn't make sense
  3534. cellsHeight = oldDataHeight;
  3535. }
  3536. }
  3537. UpdateDisplayedRows(this.DisplayData.FirstDisplayedScrollingRow, cellsHeight);
  3538. if (allowVertScrollbar &&
  3539. DoubleUtil.GreaterThan(cellsHeight, 0) &&
  3540. DoubleUtil.LessThanOrClose(vertScrollBarWidth, cellsWidth) &&
  3541. this.DisplayData.NumTotallyDisplayedScrollingRows != this.RowCount)
  3542. {
  3543. cellsWidth -= vertScrollBarWidth;
  3544. Debug.Assert(cellsWidth >= 0);
  3545. needVertScrollbar = true;
  3546. }
  3547. this.DisplayData.FirstDisplayedScrollingCol = ComputeFirstVisibleScrollingColumn();
  3548. // we compute the number of visible columns only after we set up the vertical scroll bar.
  3549. ComputeDisplayedColumns();
  3550. if (allowHorizScrollbar &&
  3551. needVertScrollbar && !needHorizScrollbar &&
  3552. DoubleUtil.GreaterThan(totalVisibleWidth, cellsWidth) &&
  3553. DoubleUtil.LessThan(totalVisibleFrozenWidth, cellsWidth) &&
  3554. DoubleUtil.LessThanOrClose(horizScrollBarHeight, cellsHeight))
  3555. {
  3556. cellsWidth += vertScrollBarWidth;
  3557. cellsHeight -= horizScrollBarHeight;
  3558. Debug.Assert(cellsHeight >= 0);
  3559. needVertScrollbar = false;
  3560. UpdateDisplayedRows(this.DisplayData.FirstDisplayedScrollingRow, cellsHeight);
  3561. if (cellsHeight > 0 &&
  3562. vertScrollBarWidth <= cellsWidth &&
  3563. this.DisplayData.NumTotallyDisplayedScrollingRows != this.RowCount)
  3564. {
  3565. cellsWidth -= vertScrollBarWidth;
  3566. Debug.Assert(cellsWidth >= 0);
  3567. needVertScrollbar = true;
  3568. }
  3569. if (needVertScrollbar)
  3570. {
  3571. needHorizScrollbar = true;
  3572. }
  3573. else
  3574. {
  3575. needHorizScrollbar = needHorizScrollbarWithoutVertScrollbar;
  3576. }
  3577. }
  3578. }
  3579. else if (forceHorizScrollbar && !forceVertScrollbar)
  3580. {
  3581. if (allowVertScrollbar)
  3582. {
  3583. if (cellsHeight > 0 &&
  3584. DoubleUtil.LessThanOrClose(vertScrollBarWidth, cellsWidth) &&
  3585. this.DisplayData.NumTotallyDisplayedScrollingRows != this.RowCount)
  3586. {
  3587. cellsWidth -= vertScrollBarWidth;
  3588. Debug.Assert(cellsWidth >= 0);
  3589. needVertScrollbar = true;
  3590. }
  3591. this.DisplayData.FirstDisplayedScrollingCol = ComputeFirstVisibleScrollingColumn();
  3592. ComputeDisplayedColumns();
  3593. }
  3594. needHorizScrollbar = totalVisibleWidth > cellsWidth && totalVisibleFrozenWidth < cellsWidth;
  3595. }
  3596. else if (!forceHorizScrollbar && forceVertScrollbar)
  3597. {
  3598. if (allowHorizScrollbar)
  3599. {
  3600. if (cellsWidth > 0 &&
  3601. DoubleUtil.LessThanOrClose(horizScrollBarHeight, cellsHeight) &&
  3602. DoubleUtil.GreaterThan(totalVisibleWidth, cellsWidth) &&
  3603. DoubleUtil.LessThan(totalVisibleFrozenWidth, cellsWidth))
  3604. {
  3605. cellsHeight -= horizScrollBarHeight;
  3606. Debug.Assert(cellsHeight >= 0);
  3607. needHorizScrollbar = true;
  3608. UpdateDisplayedRows(this.DisplayData.FirstDisplayedScrollingRow, cellsHeight);
  3609. }
  3610. this.DisplayData.FirstDisplayedScrollingCol = ComputeFirstVisibleScrollingColumn();
  3611. ComputeDisplayedColumns();
  3612. }
  3613. needVertScrollbar = this.DisplayData.NumTotallyDisplayedScrollingRows != this.RowCount;
  3614. }
  3615. else
  3616. {
  3617. Debug.Assert(forceHorizScrollbar && forceVertScrollbar);
  3618. Debug.Assert(allowHorizScrollbar && allowVertScrollbar);
  3619. this.DisplayData.FirstDisplayedScrollingCol = ComputeFirstVisibleScrollingColumn();
  3620. ComputeDisplayedColumns();
  3621. needVertScrollbar = this.DisplayData.NumTotallyDisplayedScrollingRows != this.RowCount;
  3622. needHorizScrollbar = totalVisibleWidth > cellsWidth && totalVisibleFrozenWidth < cellsWidth;
  3623. }
  3624. UpdateHorizontalScrollBar(needHorizScrollbar, forceHorizScrollbar, totalVisibleWidth, totalVisibleFrozenWidth, cellsWidth);
  3625. UpdateVerticalScrollBar(needVertScrollbar, forceVertScrollbar, totalVisibleHeight, cellsHeight);
  3626. if (this._topRightCornerHeader != null)
  3627. {
  3628. // Show the TopRightHeaderCell based on vertical ScrollBar visibility
  3629. if (this.AreColumnHeadersVisible &&
  3630. this._vScrollBar != null && this._vScrollBar.Visibility == Visibility.Visible)
  3631. {
  3632. this._topRightCornerHeader.Visibility = Visibility.Visible;
  3633. }
  3634. else
  3635. {
  3636. this._topRightCornerHeader.Visibility = Visibility.Collapsed;
  3637. }
  3638. }
  3639. this.DisplayData.FullyRecycleRows();
  3640. }
  3641. // Makes sure horizontal layout is updated to reflect any changes that affect it
  3642. private void EnsureHorizontalLayout()
  3643. {
  3644. this.ColumnsInternal.EnsureVisibleEdgedColumnsWidth();
  3645. InvalidateColumnHeadersMeasure();
  3646. InvalidateRowsMeasure(true);
  3647. InvalidateMeasure();
  3648. }
  3649. private void EnsureRowHeaderWidth()
  3650. {
  3651. if (this.AreRowHeadersVisible)
  3652. {
  3653. if (this.AreColumnHeadersVisible)
  3654. {
  3655. EnsureTopLeftCornerHeader();
  3656. }
  3657. bool updated = false;
  3658. if (_rowsPresenter != null)
  3659. {
  3660. foreach (DataGridRow row in _rowsPresenter.Children)
  3661. {
  3662. // If the RowHeader resulted in a different width the last time it was measured, we need
  3663. // to re-measure it
  3664. if (row.HeaderCell != null && row.HeaderCell.DesiredSize.Width != this.ActualRowHeaderWidth)
  3665. {
  3666. row.HeaderCell.InvalidateMeasure();
  3667. updated = true;
  3668. }
  3669. }
  3670. }
  3671. if (updated)
  3672. {
  3673. // We need to update the width of the horizontal scrollbar if the rowHeaders' width actually changed
  3674. InvalidateMeasure();
  3675. }
  3676. }
  3677. }
  3678. private void EnsureRowsPresenterVisibility()
  3679. {
  3680. if (_rowsPresenter != null)
  3681. {
  3682. // RowCount doesn't need to be considered, doing so might cause extra Visibility changes
  3683. _rowsPresenter.Visibility = this.ColumnsInternal.FirstVisibleColumn == null ? Visibility.Collapsed : Visibility.Visible;
  3684. }
  3685. }
  3686. private void EnsureTopLeftCornerHeader()
  3687. {
  3688. if (_topLeftCornerHeader != null)
  3689. {
  3690. _topLeftCornerHeader.Visibility = this.HeadersVisibility == DataGridHeadersVisibility.All ? Visibility.Visible : Visibility.Collapsed;
  3691. if (_topLeftCornerHeader.Visibility == Visibility.Visible)
  3692. {
  3693. if (!double.IsNaN(this.RowHeaderWidth))
  3694. {
  3695. // RowHeaderWidth is set explicitly so we should use that
  3696. _topLeftCornerHeader.Width = this.RowHeaderWidth;
  3697. }
  3698. else if (this.RowCount > 0)
  3699. {
  3700. // RowHeaders AutoSize and we have at least 1 row so take the desired width
  3701. _topLeftCornerHeader.Width = this.RowHeadersDesiredWidth;
  3702. }
  3703. }
  3704. }
  3705. }
  3706. private void InvalidateCellsArrange()
  3707. {
  3708. if (_rowsPresenter != null)
  3709. {
  3710. foreach (DataGridRow row in _rowsPresenter.Children)
  3711. {
  3712. row.InvalidateHorizontalArrange();
  3713. }
  3714. }
  3715. }
  3716. private void InvalidateColumnHeadersArrange()
  3717. {
  3718. if (_columnHeadersPresenter != null)
  3719. {
  3720. _columnHeadersPresenter.InvalidateArrange();
  3721. }
  3722. }
  3723. private void InvalidateColumnHeadersMeasure()
  3724. {
  3725. if (_columnHeadersPresenter != null)
  3726. {
  3727. EnsureColumnHeadersVisibility();
  3728. _columnHeadersPresenter.InvalidateMeasure();
  3729. }
  3730. }
  3731. private void InvalidateRowsArrange()
  3732. {
  3733. if (_rowsPresenter != null)
  3734. {
  3735. _rowsPresenter.InvalidateArrange();
  3736. }
  3737. }
  3738. private void InvalidateRowsMeasure(bool invalidateIndividualRows)
  3739. {
  3740. if (_rowsPresenter != null)
  3741. {
  3742. _rowsPresenter.InvalidateMeasure();
  3743. if (invalidateIndividualRows)
  3744. {
  3745. foreach (UIElement child in _rowsPresenter.Children)
  3746. {
  3747. child.InvalidateMeasure();
  3748. }
  3749. }
  3750. }
  3751. }
  3752. private void DataGrid_GotFocus(object sender, RoutedEventArgs e)
  3753. {
  3754. if (!this.ContainsFocus)
  3755. {
  3756. //
  3757. this._focusedRow = null;
  3758. this.ContainsFocus = true;
  3759. Control focusedControl = e.OriginalSource as Control;
  3760. if (focusedControl != null && focusedControl != this)
  3761. {
  3762. DataGridCell dataGridCell = GetOwningCell(focusedControl);
  3763. if (dataGridCell != null && dataGridCell.OwningColumn is DataGridTemplateColumn)
  3764. {
  3765. this._editingTemplateControl = focusedControl;
  3766. }
  3767. }
  3768. ApplyDisplayedRowsState(this.DisplayData.FirstDisplayedScrollingRow, this.DisplayData.LastDisplayedScrollingRow);
  3769. if (this.CurrentColumnIndex != -1 && this.DisplayData.IsRowDisplayed(this.CurrentRowIndex))
  3770. {
  3771. this.DisplayData.GetDisplayedRow(this.CurrentRowIndex).Cells[this.CurrentColumnIndex].ApplyCellState(true /*animate*/);
  3772. }
  3773. }
  3774. // Keep track of which row contains the newly focused element
  3775. DataGridRow focusedRow = null;
  3776. DependencyObject focusedElement = e.OriginalSource as DependencyObject;
  3777. while (focusedElement != null)
  3778. {
  3779. focusedRow = focusedElement as DataGridRow;
  3780. if (focusedRow != null && focusedRow.OwningGrid == this)
  3781. {
  3782. _focusedRow = focusedRow;
  3783. break;
  3784. }
  3785. focusedElement = VisualTreeHelper.GetParent(focusedElement);
  3786. }
  3787. }
  3788. private void DataGrid_KeyDown(object sender, KeyEventArgs e)
  3789. {
  3790. //
  3791. if (!e.Handled)
  3792. {
  3793. e.Handled = ProcessDataGridKey(e);
  3794. }
  3795. }
  3796. private void DataGrid_KeyUp(object sender, KeyEventArgs e)
  3797. {
  3798. //
  3799. if (e.Key == Key.Tab && this.CurrentColumnIndex != -1 && e.OriginalSource == this)
  3800. {
  3801. bool success = ScrollIntoView(this.CurrentColumnIndex, this.CurrentRowIndex, false /*forCurrentCellChange*/);
  3802. Debug.Assert(success);
  3803. if (this.CurrentColumnIndex != -1 && this.SelectedItem == null)
  3804. {
  3805. SetRowSelection(this.CurrentRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  3806. }
  3807. }
  3808. }
  3809. private void DataGrid_LostFocus(object sender, RoutedEventArgs e)
  3810. {
  3811. if (this.ContainsFocus)
  3812. {
  3813. this.ContainsFocus = false;
  3814. ApplyDisplayedRowsState(this.DisplayData.FirstDisplayedScrollingRow, this.DisplayData.LastDisplayedScrollingRow);
  3815. if (this.CurrentColumnIndex != -1 && this.DisplayData.IsRowDisplayed(this.CurrentRowIndex))
  3816. {
  3817. this.DisplayData.GetDisplayedRow(this.CurrentRowIndex).Cells[this.CurrentColumnIndex].ApplyCellState(true /*animate*/);
  3818. }
  3819. }
  3820. }
  3821. /// <summary>
  3822. /// Called when the edited element of a column gains focus
  3823. /// </summary>
  3824. private void EditingElement_GotFocus(object sender, RoutedEventArgs e)
  3825. {
  3826. //
  3827. FrameworkElement element = sender as FrameworkElement;
  3828. if (element != null)
  3829. {
  3830. // No longer interested in the GotFocus event
  3831. element.GotFocus -= new RoutedEventHandler(EditingElement_GotFocus);
  3832. this._editingElementGotFocusListeners--;
  3833. Debug.Assert(this._editingElementGotFocusListeners >= 0);
  3834. //
  3835. // but need to know when the element loses focus
  3836. element.LostFocus += new RoutedEventHandler(EditingElement_LostFocus);
  3837. this._editingElementLostFocusListeners++;
  3838. //
  3839. }
  3840. }
  3841. /// <summary>
  3842. /// Called when the edited element of a column loses focus
  3843. /// </summary>
  3844. private void EditingElement_LostFocus(object sender, RoutedEventArgs e)
  3845. {
  3846. //
  3847. FrameworkElement element = sender as FrameworkElement;
  3848. if (element != null)
  3849. {
  3850. // No longer interested in the LostFocus event
  3851. element.LostFocus -= new RoutedEventHandler(EditingElement_LostFocus);
  3852. this._editingElementLostFocusListeners--;
  3853. Debug.Assert(this._editingElementLostFocusListeners >= 0);
  3854. //
  3855. // An element outside the DataGrid may have received focus. We need to know
  3856. // when the edited element receives it back, if ever.
  3857. element.GotFocus += new RoutedEventHandler(EditingElement_GotFocus);
  3858. Debug.Assert(this._editingElementGotFocusListeners >= 0);
  3859. this._editingElementGotFocusListeners++;
  3860. //
  3861. if (this.CurrentColumn != null && this.CurrentColumn is DataGridBoundColumn)
  3862. {
  3863. // The edited element may need to repopulate its content asynchronously
  3864. this.Dispatcher.BeginInvoke(new Action(PopulateUneditedBoundCellContent), null);
  3865. }
  3866. // End editing if focus leaves the DataGrid entirely
  3867. bool isDataGridChild = false;
  3868. DependencyObject focusedElement = FocusManager.GetFocusedElement() as DependencyObject;
  3869. while (focusedElement != null)
  3870. {
  3871. if (focusedElement == this._editingRow || focusedElement == this)
  3872. {
  3873. isDataGridChild = true;
  3874. break;
  3875. }
  3876. focusedElement = VisualTreeHelper.GetParent(focusedElement);
  3877. }
  3878. if (!isDataGridChild)
  3879. {
  3880. CommitEdit(DataGridEditingUnit.Row, true /*exitEditingMode*/);
  3881. }
  3882. }
  3883. }
  3884. private void EditingElement_Loaded(object sender, RoutedEventArgs e)
  3885. {
  3886. //
  3887. FrameworkElement element = sender as FrameworkElement;
  3888. if (element != null)
  3889. {
  3890. //
  3891. element.Loaded -= new RoutedEventHandler(EditingElement_Loaded);
  3892. }
  3893. PreparingCellForEditPrivate(element);
  3894. }
  3895. [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  3896. private bool EndCellEdit(bool commitCellEdit, bool exitEditingMode, bool keepFocus)
  3897. {
  3898. //
  3899. if (this._editingColumnIndex == -1)
  3900. {
  3901. //
  3902. return true;
  3903. }
  3904. Debug.Assert(this._editingRow != null);
  3905. Debug.Assert(this._editingColumnIndex >= 0);
  3906. Debug.Assert(this._editingColumnIndex < this.ColumnsItemsInternal.Count);
  3907. Debug.Assert(this._editingColumnIndex == this.CurrentColumnIndex);
  3908. Debug.Assert(this.EditingRowIndex == this.CurrentRowIndex);
  3909. int curRowIndex = this.CurrentRowIndex;
  3910. int curColIndex = this.CurrentColumnIndex;
  3911. //
  3912. if (!commitCellEdit)
  3913. {
  3914. CancelCellEdit(exitEditingMode);
  3915. }
  3916. if (this._editingColumnIndex == -1 ||
  3917. curRowIndex != this.CurrentRowIndex ||
  3918. curColIndex != this.CurrentColumnIndex)
  3919. {
  3920. //
  3921. return true;
  3922. }
  3923. Debug.Assert(this._editingRow != null);
  3924. Debug.Assert(this.EditingRowIndex == curRowIndex);
  3925. Debug.Assert(this._editingColumnIndex != -1);
  3926. Debug.Assert(this._editingColumnIndex == this.CurrentColumnIndex);
  3927. if (exitEditingMode)
  3928. {
  3929. this._editingColumnIndex = -1;
  3930. this._editingTemplateControl = null;
  3931. this._editingRow.Cells[this.CurrentColumnIndex].ApplyCellState(true /*animate*/);
  3932. //
  3933. this.IsTabStop = true;
  3934. if (keepFocus)
  3935. {
  3936. bool success = Focus();
  3937. Debug.Assert(success);
  3938. }
  3939. }
  3940. if (exitEditingMode || commitCellEdit)
  3941. {
  3942. DataGridCell cell = this._editingRow.Cells[this.CurrentColumnIndex];
  3943. if (!(this.CurrentColumn is DataGridBoundColumn))
  3944. {
  3945. //
  3946. PopulateCellContent(false /*forceTemplating*/, !exitEditingMode /*isCellEdited*/, this.CurrentColumn, this._editingRow, cell);
  3947. }
  3948. else if (this._editingBoundCells.Count > 0)
  3949. {
  3950. Debug.Assert(this._editingBoundCells.Contains(cell));
  3951. this._editingBoundCells.Remove(cell);
  3952. PopulateCellContent(false /*forceTemplating*/, !exitEditingMode /*isCellEdited*/, this.CurrentColumn, this._editingRow, cell);
  3953. }
  3954. if (this._editingElementLostFocusListeners == 0 && this._editingElementGotFocusListeners > 0)
  3955. {
  3956. FrameworkElement element = cell.Content as FrameworkElement;
  3957. if (element != null)
  3958. {
  3959. element.GotFocus -= new RoutedEventHandler(EditingElement_GotFocus);
  3960. this._editingElementGotFocusListeners--;
  3961. }
  3962. }
  3963. }
  3964. return true;
  3965. }
  3966. private bool EndRowEdit(bool commitRowEdit, bool exitEditingMode)
  3967. {
  3968. if (this._editingRow == null)
  3969. {
  3970. return true;
  3971. }
  3972. if (commitRowEdit)
  3973. {
  3974. CommitRowEdit(exitEditingMode);
  3975. }
  3976. else
  3977. {
  3978. CancelRowEdit(exitEditingMode);
  3979. }
  3980. if (exitEditingMode)
  3981. {
  3982. Debug.Assert(this._editingRow != null);
  3983. DataGridRow editingRow = this._editingRow;
  3984. this._editingRow = null;
  3985. if (!this.DisplayData.IsRowDisplayed(editingRow.Index) && this._rowsPresenter != null && editingRow != this._focusedRow)
  3986. {
  3987. //
  3988. this._rowsPresenter.Children.Remove(editingRow);
  3989. }
  3990. else
  3991. {
  3992. editingRow.ApplyState(true /*animate*/);
  3993. }
  3994. }
  3995. return true;
  3996. }
  3997. // Applies the given Style to the column's HeaderCell if the HeaderCell does not already
  3998. // have a Style applied
  3999. private static void EnsureColumnHeaderCellStyle(DataGridColumn column, Style oldDataGridStyle, Style newDataGridStyle)
  4000. {
  4001. Debug.Assert(column != null);
  4002. //
  4003. if (column != null && (column.HeaderCell.Style == null || column.HeaderCell.Style == oldDataGridStyle))
  4004. {
  4005. column.HeaderCell.Style = newDataGridStyle;
  4006. }
  4007. }
  4008. private void EnsureColumnHeadersVisibility()
  4009. {
  4010. if (_columnHeadersPresenter != null)
  4011. {
  4012. _columnHeadersPresenter.Visibility = this.AreColumnHeadersVisible ? Visibility.Visible : Visibility.Collapsed;
  4013. }
  4014. }
  4015. private static void EnsureRowStyle(DataGridRow row, Style oldDataGridRowStyle, Style newDataGridRowStyle)
  4016. {
  4017. Debug.Assert(row != null);
  4018. if (newDataGridRowStyle != null)
  4019. {
  4020. //
  4021. if (row != null && (row.Style == null || row.Style == oldDataGridRowStyle))
  4022. {
  4023. row.Style = newDataGridRowStyle;
  4024. }
  4025. }
  4026. }
  4027. private void EnsureVerticalGridLines()
  4028. {
  4029. double totalColumnsWidth = 0;
  4030. foreach (DataGridColumn column in this.ColumnsInternal)
  4031. {
  4032. totalColumnsWidth += column.ActualWidth;
  4033. if (this.AreColumnHeadersVisible)
  4034. {
  4035. column.HeaderCell.SeparatorVisibility = (column != this.ColumnsInternal.LastVisibleColumn || totalColumnsWidth < this.CellsWidth) ?
  4036. Visibility.Visible : Visibility.Collapsed;
  4037. }
  4038. }
  4039. foreach (DataGridRow row in this._rowsPresenter.Children)
  4040. {
  4041. foreach (DataGridCell cell in row.Cells)
  4042. {
  4043. cell.EnsureGridLine(this.ColumnsInternal.LastVisibleColumn);
  4044. }
  4045. }
  4046. }
  4047. /// <summary>
  4048. /// Exits editing mode without trying to commit or revert the editing, and
  4049. /// without repopulating the edited row's cell.
  4050. /// </summary>
  4051. private void ExitEdit(bool keepFocus)
  4052. {
  4053. if (this._editingRow == null)
  4054. {
  4055. Debug.Assert(this._editingColumnIndex == -1);
  4056. return;
  4057. }
  4058. if (this._editingColumnIndex != -1)
  4059. {
  4060. Debug.Assert(this._editingColumnIndex >= 0);
  4061. Debug.Assert(this._editingColumnIndex < this.ColumnsItemsInternal.Count);
  4062. Debug.Assert(this._editingColumnIndex == this.CurrentColumnIndex);
  4063. Debug.Assert(this.EditingRowIndex == this.CurrentRowIndex);
  4064. this._editingColumnIndex = -1;
  4065. this._editingRow.Cells[this.CurrentColumnIndex].ApplyCellState(false /*animate*/);
  4066. }
  4067. //
  4068. this.IsTabStop = true;
  4069. if (!this.DisplayData.IsRowDisplayed(this._editingRow.Index) && (this._rowsPresenter != null))
  4070. {
  4071. _rowsPresenter.Children.Remove(this._editingRow);
  4072. }
  4073. else
  4074. {
  4075. this._editingRow.ApplyState(true /*animate*/);
  4076. }
  4077. this._editingRow = null;
  4078. if (keepFocus)
  4079. {
  4080. bool success = Focus();
  4081. Debug.Assert(success);
  4082. }
  4083. }
  4084. private void FlushSelectionChanged()
  4085. {
  4086. if (this._selectionChanged)
  4087. {
  4088. SelectionChangedEventArgs eventArgs = new SelectionChangedEventArgs(this._removedSelectedItems, this._addedSelectedItems);
  4089. OnSelectionChanged(eventArgs);
  4090. this._addedSelectedItems.Clear();
  4091. this._removedSelectedItems.Clear();
  4092. }
  4093. }
  4094. private bool FocusEditingCell(bool setFocus)
  4095. {
  4096. Debug.Assert(this.CurrentColumnIndex >= 0);
  4097. Debug.Assert(this.CurrentColumnIndex < this.Columns.Count);
  4098. Debug.Assert(this.CurrentRowIndex >= -1);
  4099. Debug.Assert(this.CurrentRowIndex < this.RowCount);
  4100. Debug.Assert(this.EditingRowIndex == this.CurrentRowIndex);
  4101. Debug.Assert(this._editingColumnIndex != -1);
  4102. //
  4103. this.IsTabStop = false;
  4104. this._focusEditingControl = false;
  4105. DataGridCell dataGridCell = this._editingRow.Cells[this._editingColumnIndex];
  4106. if (dataGridCell.OwningColumn is DataGridBoundColumn)
  4107. {
  4108. Control editingControl = dataGridCell.Content as Control;
  4109. if (editingControl != null)
  4110. {
  4111. editingControl.IsTabStop = true;
  4112. editingControl.TabIndex = this.TabIndex;
  4113. if (setFocus)
  4114. {
  4115. this._focusEditingControl = !editingControl.Focus();
  4116. }
  4117. }
  4118. }
  4119. else if (setFocus && this._editingTemplateControl != null && this._editingTemplateControl.IsTabStop)
  4120. {
  4121. return this._editingTemplateControl.Focus();
  4122. }
  4123. return false;
  4124. }
  4125. // Calculates the amount to scroll for the ScrollLeft button
  4126. // This is a method rather than a property to emphasize a calculation
  4127. private double GetHorizontalSmallScrollDecrease()
  4128. {
  4129. // If the first column is covered up, scroll to the start of it when the user clicks the left button
  4130. if (_negHorizontalOffset > 0)
  4131. {
  4132. return _negHorizontalOffset;
  4133. }
  4134. else
  4135. {
  4136. // The entire first column is displayed, show the entire previous column when the user clicks
  4137. // the left button
  4138. DataGridColumn previousColumn = this.ColumnsInternal.GetPreviousVisibleScrollingColumn(
  4139. this.ColumnsInternal[DisplayData.FirstDisplayedScrollingCol]);
  4140. if (previousColumn != null)
  4141. {
  4142. return GetEdgedColumnWidth(previousColumn);
  4143. }
  4144. else
  4145. {
  4146. // There's no previous column so don't move
  4147. return 0;
  4148. }
  4149. }
  4150. }
  4151. // Calculates the amount to scroll for the ScrollRight button
  4152. // This is a method rather than a property to emphasize a calculation
  4153. private double GetHorizontalSmallScrollIncrease()
  4154. {
  4155. if (this.DisplayData.FirstDisplayedScrollingCol >= 0)
  4156. {
  4157. return GetEdgedColumnWidth(this.ColumnsInternal[DisplayData.FirstDisplayedScrollingCol]) - _negHorizontalOffset;
  4158. }
  4159. return 0;
  4160. }
  4161. // Calculates the amount the ScrollDown button should scroll
  4162. // This is a method rather than a property to emphasize that calculations are taking place
  4163. private double GetVerticalSmallScrollIncrease()
  4164. {
  4165. if (this.DisplayData.FirstDisplayedScrollingRow >= 0)
  4166. {
  4167. return GetEdgedExactRowHeight(this.DisplayData.FirstDisplayedScrollingRow) - this.NegVerticalOffset;
  4168. }
  4169. return 0;
  4170. }
  4171. private void HorizontalScrollBar_Scroll(object sender, ScrollEventArgs e)
  4172. {
  4173. ProcessHorizontalScroll(e.ScrollEventType);
  4174. }
  4175. private bool IsColumnOutOfBounds(int columnIndex)
  4176. {
  4177. return columnIndex >= this.ColumnsItemsInternal.Count || columnIndex < 0;
  4178. }
  4179. private bool IsInnerCellOutOfBounds(int columnIndex, int rowIndex)
  4180. {
  4181. return IsColumnOutOfBounds(columnIndex) || IsRowOutOfBounds(rowIndex);
  4182. }
  4183. //
  4184. private bool IsRowOutOfBounds(int rowIndex)
  4185. {
  4186. return rowIndex >= this.RowCount || rowIndex < -1 /**/;
  4187. }
  4188. private void MakeFirstDisplayedCellCurrentCell()
  4189. {
  4190. if (this.CurrentColumnIndex != -1)
  4191. {
  4192. this._makeFirstDisplayedCellCurrentCellPending = false;
  4193. return;
  4194. }
  4195. // No current cell, therefore no selection either - try to set the first displayed cell to be the current one.
  4196. int firstDisplayedColumnIndex = this.FirstDisplayedColumnIndex;
  4197. int rowIndex = (this.SelectedIndex == -1) ? this.DisplayData.FirstDisplayedScrollingRow : this.SelectedIndex;
  4198. if (firstDisplayedColumnIndex != -1 && rowIndex != -1)
  4199. {
  4200. SetAndSelectCurrentCell(firstDisplayedColumnIndex,
  4201. rowIndex,
  4202. false /*forceCurrentCellSelection (unused here)*/);
  4203. this.AnchorRowIndex = rowIndex;
  4204. this._makeFirstDisplayedCellCurrentCellPending = false;
  4205. }
  4206. else
  4207. {
  4208. this._makeFirstDisplayedCellCurrentCellPending = true;
  4209. }
  4210. }
  4211. private void PopulateCellContent(bool forceTemplating, bool isCellEdited,
  4212. DataGridColumn dataGridColumn,
  4213. DataGridRow dataGridRow,
  4214. DataGridCell dataGridCell)
  4215. {
  4216. //
  4217. Debug.Assert(dataGridColumn != null);
  4218. Debug.Assert(dataGridRow != null);
  4219. Debug.Assert(dataGridRow.DataContext != null, "dataGridRow.DataContext is null");
  4220. Debug.Assert(dataGridCell != null);
  4221. FrameworkElement element = null;
  4222. //
  4223. DataGridTemplateColumn dataGridTemplateColumn = dataGridColumn as DataGridTemplateColumn;
  4224. if (dataGridTemplateColumn != null)
  4225. {
  4226. //
  4227. if (forceTemplating || dataGridTemplateColumn.HasDistinctTemplates)
  4228. {
  4229. //
  4230. DataTemplate cellTemplate = null;
  4231. //
  4232. if (isCellEdited)
  4233. {
  4234. cellTemplate = dataGridTemplateColumn.CellEditingTemplate;
  4235. if (cellTemplate == null)
  4236. {
  4237. cellTemplate = dataGridTemplateColumn.CellTemplate;
  4238. }
  4239. }
  4240. else
  4241. {
  4242. cellTemplate = dataGridTemplateColumn.CellTemplate;
  4243. if (cellTemplate == null)
  4244. {
  4245. cellTemplate = dataGridTemplateColumn.CellEditingTemplate;
  4246. }
  4247. }
  4248. if (cellTemplate == null)
  4249. {
  4250. // No cell template nor cell editing template for DataGridTemplateColumn
  4251. throw DataGridError.DataGridTemplateColumn.MissingTemplateForType(typeof(DataGridTemplateColumn));
  4252. }
  4253. element = cellTemplate.LoadContent() as FrameworkElement;
  4254. }
  4255. else if (isCellEdited)
  4256. {
  4257. PreparingCellForEditPrivate(dataGridCell.Content as FrameworkElement);
  4258. return;
  4259. }
  4260. }
  4261. else // if the column is not a template column
  4262. {
  4263. DataGridBoundColumn dataGridBoundColumn = dataGridColumn as DataGridBoundColumn;
  4264. //
  4265. if (isCellEdited)
  4266. {
  4267. element = dataGridColumn.GenerateEditingElementInternal(dataGridCell, dataGridRow.DataContext);
  4268. if (element != null)
  4269. {
  4270. //
  4271. if (dataGridBoundColumn != null && dataGridBoundColumn.EditingElementStyle != null && element.Style == null)
  4272. {
  4273. element.Style = dataGridBoundColumn.EditingElementStyle;
  4274. }
  4275. // Remember which cell needs to repopulate its content asynchronously.
  4276. this._editingBoundCells.Add(dataGridCell);
  4277. }
  4278. }
  4279. else
  4280. {
  4281. // Generate Element and apply column style if available
  4282. element = dataGridColumn.GenerateElementInternal(dataGridCell, dataGridRow.DataContext);
  4283. //
  4284. if (element != null && dataGridBoundColumn != null && dataGridBoundColumn.ElementStyle != null && element.Style == null)
  4285. {
  4286. element.Style = dataGridBoundColumn.ElementStyle;
  4287. }
  4288. }
  4289. }
  4290. if (isCellEdited && element != null)
  4291. {
  4292. //
  4293. element.Loaded += new RoutedEventHandler(EditingElement_Loaded);
  4294. // Subscribe to the GotFocus event so that the non-editing element can be generated
  4295. // asynchronously after the edited value is committed.
  4296. element.GotFocus += new RoutedEventHandler(EditingElement_GotFocus);
  4297. this._editingElementGotFocusListeners++;
  4298. //
  4299. }
  4300. dataGridCell.Content = element;
  4301. }
  4302. /// <summary>
  4303. /// Repopulates a cell that was previously edited with the non-editing element.
  4304. /// This method is invoked asynchronously after the editing element loses focus and
  4305. /// the back-end property was updated with a new value, or when the current cell
  4306. /// leaves the editing mode before the Loaded event has a chance to be raised.
  4307. /// </summary>
  4308. private void PopulateUneditedBoundCellContent()
  4309. {
  4310. //
  4311. if (this._editingBoundCells.Count > 0)
  4312. {
  4313. DataGridCell dataGridCell = this._editingBoundCells[0];
  4314. Debug.Assert(dataGridCell != null);
  4315. if (dataGridCell.OwningGrid == this)
  4316. {
  4317. Debug.Assert(dataGridCell.OwningColumn is DataGridBoundColumn);
  4318. if (dataGridCell.OwningColumn.Index != this._editingColumnIndex ||
  4319. dataGridCell.OwningRow != this._editingRow)
  4320. {
  4321. if (this._editingElementGotFocusListeners > 0)
  4322. {
  4323. // No longer interested in the GotFocus event
  4324. FrameworkElement element = dataGridCell.Content as FrameworkElement;
  4325. if (element != null)
  4326. {
  4327. element.GotFocus -= new RoutedEventHandler(EditingElement_GotFocus);
  4328. this._editingElementGotFocusListeners--;
  4329. Debug.Assert(this._editingElementGotFocusListeners >= 0);
  4330. //
  4331. }
  4332. }
  4333. this._editingBoundCells.RemoveAt(0); // 0 = the dataGridCell we were just inspecting
  4334. // Repopulate the cell with the non-editing element
  4335. PopulateCellContent(false /*forceTemplating*/, false /*isCellEdited*/,
  4336. dataGridCell.OwningColumn, dataGridCell.OwningRow, dataGridCell);
  4337. }
  4338. }
  4339. else
  4340. {
  4341. this._editingBoundCells.RemoveAt(0); // 0 = the dataGridCell we were just inspecting
  4342. }
  4343. }
  4344. }
  4345. // Returns False if we couldn't CommitEdit or if the rowIndex, columnIndex are out of bounds
  4346. private bool PrepareForScroll(int columnIndex, int rowIndex, bool forCurrentCellChange)
  4347. {
  4348. if (this.CurrentColumnIndex >= 0 &&
  4349. (this.CurrentColumnIndex != columnIndex || this.CurrentRowIndex != rowIndex))
  4350. {
  4351. if (!CommitEditForOperation(columnIndex, rowIndex, forCurrentCellChange))
  4352. {
  4353. return false;
  4354. }
  4355. if (IsInnerCellOutOfBounds(columnIndex, rowIndex))
  4356. {
  4357. return false;
  4358. }
  4359. }
  4360. return true;
  4361. }
  4362. private void PreparingCellForEditPrivate(FrameworkElement editingElement)
  4363. {
  4364. //
  4365. if (this._editingColumnIndex == -1 ||
  4366. this.CurrentColumnIndex == -1 ||
  4367. this._editingRow.Cells[this.CurrentColumnIndex].Content != editingElement)
  4368. {
  4369. // The current cell has changed since the call to BeginCellEdit. The cell needs
  4370. // to get back into non-editing mode.
  4371. DataGridCell dataGridCell = GetOwningCell(editingElement);
  4372. if (dataGridCell != null)
  4373. {
  4374. Debug.Assert(!(dataGridCell.OwningColumn is DataGridTemplateColumn));
  4375. if (this._editingBoundCells.Count > 0 && dataGridCell == this._editingBoundCells[0])
  4376. {
  4377. Debug.Assert(dataGridCell.OwningColumn is DataGridBoundColumn);
  4378. PopulateUneditedBoundCellContent();
  4379. }
  4380. //
  4381. }
  4382. //
  4383. return;
  4384. }
  4385. Debug.Assert(this._editingRow != null);
  4386. Debug.Assert(this._editingColumnIndex >= 0);
  4387. Debug.Assert(this._editingColumnIndex < this.ColumnsItemsInternal.Count);
  4388. Debug.Assert(this._editingColumnIndex == this.CurrentColumnIndex);
  4389. Debug.Assert(this.EditingRowIndex == this.CurrentRowIndex);
  4390. FocusEditingCell(this.ContainsFocus || this._focusEditingControl /*setFocus*/);
  4391. // Prepare the cell for editing and raise the PreparingCellForEdit event for all columns
  4392. DataGridColumn dataGridColumn = this.CurrentColumn;
  4393. this._uneditedValue = dataGridColumn.PrepareCellForEditInternal(editingElement, this._editingEventArgs);
  4394. OnPreparingCellForEdit(new DataGridPreparingCellForEditEventArgs(dataGridColumn, this._editingRow, this._editingEventArgs, editingElement));
  4395. //
  4396. }
  4397. private bool ProcessAKey()
  4398. {
  4399. bool ctrl, shift, alt;
  4400. KeyboardHelper.GetMetaKeyState(out ctrl, out shift, out alt);
  4401. if (ctrl && !shift && !alt && this.SelectionMode == DataGridSelectionMode.Extended)
  4402. {
  4403. SelectAll();
  4404. return true;
  4405. }
  4406. return false;
  4407. }
  4408. private bool ProcessDataGridKey(KeyEventArgs e)
  4409. {
  4410. bool focusDataGrid = false;
  4411. switch (e.Key)
  4412. {
  4413. case Key.Tab:
  4414. return ProcessTabKey(e);
  4415. case Key.Up:
  4416. focusDataGrid = ProcessUpKey();
  4417. break;
  4418. case Key.Down:
  4419. focusDataGrid = ProcessDownKey();
  4420. break;
  4421. case Key.PageDown:
  4422. focusDataGrid = ProcessNextKey();
  4423. break;
  4424. case Key.PageUp:
  4425. focusDataGrid = ProcessPriorKey();
  4426. break;
  4427. case Key.Left:
  4428. focusDataGrid = ProcessLeftKey();
  4429. break;
  4430. case Key.Right:
  4431. focusDataGrid = ProcessRightKey();
  4432. break;
  4433. case Key.F2:
  4434. return ProcessF2Key(e);
  4435. case Key.Home:
  4436. focusDataGrid = ProcessHomeKey();
  4437. break;
  4438. //
  4439. case Key.End:
  4440. focusDataGrid = ProcessEndKey();
  4441. break;
  4442. case Key.Enter:
  4443. focusDataGrid = ProcessEnterKey();
  4444. break;
  4445. case Key.Escape:
  4446. return ProcessEscapeKey();
  4447. case Key.A:
  4448. return ProcessAKey();
  4449. //
  4450. //
  4451. }
  4452. if (focusDataGrid && this.IsTabStop)
  4453. {
  4454. this.Focus();
  4455. }
  4456. return focusDataGrid;
  4457. }
  4458. [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  4459. private bool ProcessDownKeyInternal(bool shift, bool ctrl, out bool moved)
  4460. {
  4461. bool success;
  4462. DataGridColumn dataGridColumn = this.ColumnsInternal.FirstVisibleColumn;
  4463. int firstVisibleColumnIndex = (dataGridColumn == null) ? -1 : dataGridColumn.Index;
  4464. int lastRowIndex = this.LastRowIndex;
  4465. if (firstVisibleColumnIndex == -1 || lastRowIndex == -1)
  4466. {
  4467. moved = false;
  4468. return false;
  4469. }
  4470. int nextRowIndex = -1;
  4471. if (this.CurrentRowIndex != -1)
  4472. {
  4473. nextRowIndex = this.GetNextRow(this.CurrentRowIndex);
  4474. //
  4475. }
  4476. //
  4477. moved = true;
  4478. _noSelectionChangeCount++;
  4479. try
  4480. {
  4481. if (ctrl)
  4482. {
  4483. if (shift)
  4484. {
  4485. if (this.CurrentColumnIndex == -1)
  4486. {
  4487. Debug.Assert(_selectedItems.Count == 0);
  4488. SetRowSelection(lastRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  4489. success = ScrollIntoView(firstVisibleColumnIndex, lastRowIndex, false);
  4490. Debug.Assert(success);
  4491. if (IsInnerCellOutOfBounds(firstVisibleColumnIndex, lastRowIndex))
  4492. {
  4493. moved = false;
  4494. return true;
  4495. }
  4496. success = SetCurrentCellCore(firstVisibleColumnIndex, lastRowIndex/*, false, false*/);
  4497. if (!success)
  4498. {
  4499. moved = false;
  4500. }
  4501. }
  4502. else
  4503. {
  4504. if (this.SelectionMode == DataGridSelectionMode.Extended)
  4505. {
  4506. if (!PrepareForScroll(this.CurrentColumnIndex, lastRowIndex, true))
  4507. {
  4508. return false;
  4509. }
  4510. if (this.AnchorRowIndex == -1 || this.CurrentColumnIndex == -1 ||
  4511. IsRowOutOfBounds(lastRowIndex))
  4512. {
  4513. moved = false;
  4514. return true;
  4515. }
  4516. ClearRowSelection(lastRowIndex, false /*resetAnchorRowIndex*/);
  4517. Debug.Assert(this.AnchorRowIndex >= 0);
  4518. SetRowsSelection(this.AnchorRowIndex, lastRowIndex);
  4519. // Scrolling needs to be done after Selection is updated
  4520. if (!ScrollIntoView(this.CurrentColumnIndex, lastRowIndex, true))
  4521. {
  4522. return true;
  4523. }
  4524. success = SetCurrentCellCore(this.CurrentColumnIndex, lastRowIndex/*, false, false*/);
  4525. if (!success)
  4526. {
  4527. moved = false;
  4528. }
  4529. }
  4530. else
  4531. {
  4532. if (!ScrollIntoView(this.CurrentColumnIndex, lastRowIndex, true))
  4533. {
  4534. return true;
  4535. }
  4536. if (this.CurrentColumnIndex == -1 || IsRowOutOfBounds(lastRowIndex))
  4537. {
  4538. moved = false;
  4539. return true;
  4540. }
  4541. if (lastRowIndex != this.SelectedIndex)
  4542. {
  4543. SetRowSelection(this.CurrentRowIndex, false /*isSelected*/, false /*setAnchorRowIndex*/);
  4544. SetRowSelection(lastRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  4545. }
  4546. success = SetCurrentCellCore(this.CurrentColumnIndex, lastRowIndex/*, false, false*/);
  4547. if (!success)
  4548. {
  4549. moved = false;
  4550. }
  4551. }
  4552. }
  4553. }
  4554. else
  4555. {
  4556. // Ctrl without Shift
  4557. if (this.CurrentColumnIndex == -1)
  4558. {
  4559. Debug.Assert(_selectedItems.Count == 0);
  4560. SetRowSelection(lastRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  4561. success = ScrollIntoView(firstVisibleColumnIndex, lastRowIndex, false);
  4562. Debug.Assert(success);
  4563. if (IsInnerCellOutOfBounds(firstVisibleColumnIndex, lastRowIndex))
  4564. {
  4565. moved = false;
  4566. return true;
  4567. }
  4568. success = SetCurrentCellCore(firstVisibleColumnIndex, lastRowIndex/*, false, false*/);
  4569. if (!success)
  4570. {
  4571. moved = false;
  4572. }
  4573. }
  4574. else
  4575. {
  4576. if (!ScrollIntoView(this.CurrentColumnIndex, lastRowIndex, true))
  4577. {
  4578. return true;
  4579. }
  4580. if (this.CurrentColumnIndex == -1 || IsRowOutOfBounds(lastRowIndex))
  4581. {
  4582. moved = false;
  4583. return true;
  4584. }
  4585. ClearRowSelection(lastRowIndex, true /*resetAnchorRowIndex*/);
  4586. success = SetCurrentCellCore(this.CurrentColumnIndex, lastRowIndex/*, false, false*/);
  4587. if (!success)
  4588. {
  4589. moved = false;
  4590. }
  4591. }
  4592. }
  4593. }
  4594. else
  4595. {
  4596. // No Ctrl
  4597. if (shift)
  4598. {
  4599. if (this.CurrentColumnIndex == -1)
  4600. {
  4601. Debug.Assert(_selectedItems.Count == 0);
  4602. SetRowSelection(lastRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  4603. success = ScrollIntoView(firstVisibleColumnIndex, lastRowIndex, false);
  4604. Debug.Assert(success);
  4605. if (IsInnerCellOutOfBounds(firstVisibleColumnIndex, lastRowIndex))
  4606. {
  4607. moved = false;
  4608. return true;
  4609. }
  4610. success = SetCurrentCellCore(firstVisibleColumnIndex, lastRowIndex/*, false, false*/);
  4611. if (!success)
  4612. {
  4613. moved = false;
  4614. }
  4615. }
  4616. else
  4617. {
  4618. if (nextRowIndex == -1)
  4619. {
  4620. moved = false;
  4621. return true;
  4622. }
  4623. if (!ScrollIntoView(this.CurrentColumnIndex, nextRowIndex, true))
  4624. {
  4625. return true;
  4626. }
  4627. if (this.CurrentColumnIndex == -1 || IsRowOutOfBounds(nextRowIndex))
  4628. {
  4629. moved = false;
  4630. return true;
  4631. }
  4632. ClearRowSelection(false /*resetAnchorRowIndex*/);
  4633. if (this.SelectionMode == DataGridSelectionMode.Extended)
  4634. {
  4635. if (nextRowIndex >= this.AnchorRowIndex)
  4636. {
  4637. SetRowsSelection(this.AnchorRowIndex, nextRowIndex);
  4638. }
  4639. else
  4640. {
  4641. SetRowsSelection(nextRowIndex, this.AnchorRowIndex);
  4642. }
  4643. }
  4644. else
  4645. {
  4646. SetRowSelection(nextRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  4647. }
  4648. success = SetCurrentCellCore(this.CurrentColumnIndex, nextRowIndex/*, false, false*/);
  4649. if (!success)
  4650. {
  4651. moved = false;
  4652. }
  4653. }
  4654. }
  4655. else
  4656. {
  4657. if (this.CurrentColumnIndex == -1)
  4658. {
  4659. Debug.Assert(_selectedItems.Count == 0);
  4660. SetRowSelection(lastRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  4661. success = ScrollIntoView(firstVisibleColumnIndex, lastRowIndex, false);
  4662. Debug.Assert(success);
  4663. if (IsInnerCellOutOfBounds(firstVisibleColumnIndex, lastRowIndex))
  4664. {
  4665. moved = false;
  4666. return true;
  4667. }
  4668. success = SetCurrentCellCore(firstVisibleColumnIndex, lastRowIndex/*, false, false*/);
  4669. if (!success)
  4670. {
  4671. moved = false;
  4672. }
  4673. }
  4674. else
  4675. {
  4676. //
  4677. if (nextRowIndex == -1)
  4678. {
  4679. moved = false;
  4680. return true;
  4681. }
  4682. //
  4683. if (nextRowIndex != -1)
  4684. {
  4685. if (!ScrollIntoView(this.CurrentColumnIndex, nextRowIndex, true))
  4686. {
  4687. return true;
  4688. }
  4689. }
  4690. if (this.CurrentColumnIndex == -1 || IsRowOutOfBounds(nextRowIndex))
  4691. {
  4692. moved = false;
  4693. return true;
  4694. }
  4695. ClearRowSelection(true /*resetAnchorRowIndex*/);
  4696. if (nextRowIndex != -1)
  4697. {
  4698. SetRowSelection(nextRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  4699. }
  4700. success = SetCurrentCellCore(this.CurrentColumnIndex, nextRowIndex/*, false, false*/);
  4701. if (!success)
  4702. {
  4703. moved = false;
  4704. }
  4705. }
  4706. }
  4707. }
  4708. }
  4709. finally
  4710. {
  4711. this.NoSelectionChangeCount--;
  4712. }
  4713. return true;
  4714. }
  4715. private bool ProcessEscapeKey()
  4716. {
  4717. if (this._editingColumnIndex != -1)
  4718. {
  4719. // Revert the potential cell editing and exit cell editing.
  4720. EndCellEdit(false /*commitCellEdit*/, true /*exitEditingMode*/, true /*keepFocus*/);
  4721. return true;
  4722. }
  4723. else if (this._editingRow != null)
  4724. {
  4725. // Revert the potential row editing and exit row editing.
  4726. EndRowEdit(false /*commitRowEdit*/, true /*exitEditingMode*/);
  4727. return true;
  4728. }
  4729. return false;
  4730. }
  4731. private bool ProcessF2Key(KeyEventArgs e)
  4732. {
  4733. bool ctrl, shift;
  4734. KeyboardHelper.GetMetaKeyState(out ctrl, out shift);
  4735. if (!shift && !ctrl &&
  4736. this._editingColumnIndex == -1 && this.CurrentColumnIndex != -1 && GetRowSelection(this.CurrentRowIndex) &&
  4737. !GetColumnEffectiveReadOnlyState(this.CurrentColumn))
  4738. {
  4739. if (ScrollIntoView(this.CurrentColumnIndex, this.CurrentRowIndex, false))
  4740. {
  4741. BeginCellEdit(e);
  4742. }
  4743. return true;
  4744. }
  4745. return false;
  4746. }
  4747. // Ctrl Left <==> Home
  4748. private bool ProcessLeftMost(int firstVisibleColumnIndex, int firstRowIndex)
  4749. {
  4750. bool success;
  4751. this._noSelectionChangeCount++;
  4752. try
  4753. {
  4754. if (this.CurrentColumnIndex == -1)
  4755. {
  4756. Debug.Assert(_selectedItems.Count == 0);
  4757. SetRowSelection(firstRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  4758. success = ScrollIntoView(firstVisibleColumnIndex, firstRowIndex, false);
  4759. Debug.Assert(success);
  4760. if (IsInnerCellOutOfBounds(firstVisibleColumnIndex, firstRowIndex))
  4761. {
  4762. return true;
  4763. }
  4764. success = SetCurrentCellCore(firstVisibleColumnIndex, firstRowIndex/*, false, false*/);
  4765. Debug.Assert(success);
  4766. }
  4767. else
  4768. {
  4769. if (!ScrollIntoView(firstVisibleColumnIndex, this.CurrentRowIndex, true))
  4770. {
  4771. return true;
  4772. }
  4773. if (IsRowOutOfBounds(this.CurrentRowIndex) || IsColumnOutOfBounds(firstVisibleColumnIndex))
  4774. {
  4775. return true;
  4776. }
  4777. success = SetCurrentCellCore(firstVisibleColumnIndex, this.CurrentRowIndex/*, false, false*/);
  4778. Debug.Assert(success);
  4779. }
  4780. return true;
  4781. }
  4782. finally
  4783. {
  4784. this.NoSelectionChangeCount--;
  4785. }
  4786. }
  4787. // Ctrl Right <==> End
  4788. private bool ProcessRightMost(int lastVisibleColumnIndex, int firstRowIndex)
  4789. {
  4790. bool success;
  4791. this._noSelectionChangeCount++;
  4792. try
  4793. {
  4794. if (this.CurrentColumnIndex == -1)
  4795. {
  4796. Debug.Assert(_selectedItems.Count == 0);
  4797. SetRowSelection(firstRowIndex, true /*isSelected*/, true /*setAnchorRowIndex*/);
  4798. success = ScrollIntoView(lastVisibleColumnIndex, firstRowIndex, false);
  4799. Debug.Assert(success);
  4800. if (IsInnerCellOutOfBounds(lastVisibleColumnIndex, firstRowIndex))
  4801. {
  4802. return true;
  4803. }
  4804. success = SetCurrentCellCore(lastVisibleColumnIndex, firstRowIndex/*, false, false*/);
  4805. Debug.Assert(success);
  4806. }
  4807. else
  4808. {
  4809. if (!ScrollIntoView(lastVisibleColumnIndex, this.CurrentRowIndex, true))
  4810. {
  4811. return true;
  4812. }
  4813. if (IsRowOutOfBounds(this.CurrentRowIndex) || IsColumnOutOfBounds(lastVisibleColumnIndex))
  4814. {
  4815. return true;
  4816. }
  4817. success = SetCurrentCellCore(lastVisibleColumnIndex, this.CurrentRowIndex/*, false, false*/);
  4818. Debug.Assert(success);
  4819. }
  4820. }
  4821. finally
  4822. {
  4823. this.NoSelectionChangeCount--;
  4824. }
  4825. return true;
  4826. }
  4827. private bool ProcessTabKey(KeyEventArgs e)
  4828. {
  4829. bool ctrl, shift;
  4830. KeyboardHelper.GetMetaKeyState(out ctrl, out shift);
  4831. if (ctrl || this._editingColumnIndex == -1 || this.IsReadOnly)
  4832. {
  4833. //Go to the next/previous control on the page when
  4834. // - Ctrl key is used
  4835. // - Potential current cell is not edited, or the datagrid is read-only.
  4836. return false;
  4837. }
  4838. // Try to locate a writable cell before/after the current cell
  4839. Debug.Assert(this.CurrentColumnIndex != -1);
  4840. Debug.Assert(this.CurrentRowIndex != -1);
  4841. int neighborVisibleWritableColumnIndex, neighborRowIndex;
  4842. DataGridColumn dataGridColumn;
  4843. if (shift)
  4844. {
  4845. dataGridColumn = this.ColumnsInternal.GetPreviousVisibleWritableColumn(this.Columns[this.CurrentColumnIndex]);
  4846. neighborRowIndex = GetPreviousRow(this.CurrentRowIndex);
  4847. }
  4848. else
  4849. {
  4850. dataGridColumn = this.ColumnsInternal.GetNextVisibleWritableColumn(this.Columns[this.CurrentColumnIndex]);
  4851. neighborRowIndex = GetNextRow(this.CurrentRowIndex);
  4852. }
  4853. neighborVisibleWritableColumnIndex = (dataGridColumn == null) ? -1 : dataGridColumn.Index;
  4854. if (neighborVisibleWritableColumnIndex == -1 && neighborRowIndex == -1)
  4855. {
  4856. // There is no previous/next row and no previous/next writable cell on the current row
  4857. return false;
  4858. }
  4859. int targetRowIndex = -1, targetColumnIndex = -1;
  4860. bool success;
  4861. this._noSelectionChangeCount++;
  4862. try
  4863. {
  4864. if (neighborVisibleWritableColumnIndex == -1)
  4865. {
  4866. targetRowIndex = neighborRowIndex;
  4867. if (shift)
  4868. {
  4869. Debug.Assert(this.ColumnsInternal.LastVisibleWritableColumn != null);
  4870. targetColumnIndex = this.ColumnsInternal.LastVisibleWritableColumn.Index;
  4871. }
  4872. else
  4873. {
  4874. Debug.Assert(this.ColumnsInternal.FirstVisibleWritableColumn != null);
  4875. targetColumnIndex = this.ColumnsInternal.FirstVisibleWritableColumn.Index;
  4876. }
  4877. }
  4878. else
  4879. {
  4880. targetRowIndex = this.CurrentRowIndex;
  4881. targetColumnIndex = neighborVisibleWritableColumnIndex;
  4882. }
  4883. if (!ScrollIntoView(targetColumnIndex, targetRowIndex, true /*forCurrentCellChange*/))
  4884. {
  4885. return true;
  4886. }
  4887. if (targetRowIndex != this.CurrentRowIndex || (this.SelectionMode == DataGridSelectionMode.Extended))
  4888. {
  4889. if (IsRowOutOfBounds(targetRowIndex))
  4890. {
  4891. return true;
  4892. }
  4893. ClearRowSelection(targetRowIndex /*rowIndexException*/, true /*setAnchorRowIndex*/);
  4894. }
  4895. if (IsInnerCellOutOfBounds(targetColumnIndex, targetRowIndex))
  4896. {
  4897. return true;
  4898. }
  4899. success = SetCurrentCellCore(targetColumnIndex, targetRowIndex/*, false, false*/);
  4900. }
  4901. finally
  4902. {
  4903. this.NoSelectionChangeCount--;
  4904. }
  4905. if (success)
  4906. {
  4907. Debug.Assert(this.ContainsFocus);
  4908. success = BeginCellEdit(e);
  4909. }
  4910. return true;
  4911. }
  4912. private void RemoveDisplayedColumnHeader(DataGridColumn dataGridColumn)
  4913. {
  4914. if (this.AreColumnHeadersVisible && _columnHeadersPresenter != null)
  4915. {
  4916. _columnHeadersPresenter.Children.RemoveAt(dataGridColumn.Index);
  4917. }
  4918. }
  4919. private void RemoveDisplayedColumnHeaders()
  4920. {
  4921. if (_columnHeadersPresenter != null)
  4922. {
  4923. _columnHeadersPresenter.Children.Clear();
  4924. }
  4925. this.ColumnsInternal.FillerColumn.IsRepresented = false;
  4926. }
  4927. private void ResetCurrentCellCore()
  4928. {
  4929. if (this.CurrentColumnIndex != -1 &&
  4930. !SetCurrentCellCore(-1, -1))
  4931. {
  4932. // Edited value couldn't be committed or aborted
  4933. throw DataGridError.DataGrid.CommitFailedCannotCompleteOperation();
  4934. }
  4935. }
  4936. private void SelectAll()
  4937. {
  4938. SetRowsSelection(0, this.RowCount - 1);
  4939. }
  4940. private bool SetAndSelectCurrentCell(int columnIndex,
  4941. int rowIndex,
  4942. bool forceCurrentCellSelection)
  4943. {
  4944. try
  4945. {
  4946. this._noSelectionChangeCount++;
  4947. if (!SetCurrentCellCore(columnIndex, rowIndex))
  4948. {
  4949. return false;
  4950. }
  4951. if (IsInnerCellOutOfBounds(columnIndex, rowIndex))
  4952. {
  4953. return false;
  4954. }
  4955. if (!GetRowSelection(rowIndex))
  4956. {
  4957. if (forceCurrentCellSelection)
  4958. {
  4959. SelectRow(rowIndex, true /*isSelected*/);
  4960. this._selectionChanged = true;
  4961. }
  4962. else
  4963. {
  4964. if (this.SelectionMode == DataGridSelectionMode.Extended && this.SelectedItems.Count > 1)
  4965. {
  4966. return true; // Do not discard the multi-selection
  4967. }
  4968. if (this.SelectedItems.Count == 1)
  4969. {
  4970. int selectedIndex = this.DataConnection.IndexOf(this.SelectedItem);
  4971. if (selectedIndex != rowIndex)
  4972. {
  4973. return true; // Do not change a single selection that does not match the new current cell
  4974. }
  4975. }
  4976. SelectRow(rowIndex, true /*isSelected*/);
  4977. this._selectionChanged = true;
  4978. }
  4979. }
  4980. }
  4981. finally
  4982. {
  4983. this.NoSelectionChangeCount--;
  4984. }
  4985. return true;
  4986. }
  4987. // columnIndex = 2, rowIndex = -1 --> current cell belongs to the 'new row'.
  4988. // columnIndex = 2, rowIndex = 2 --> current cell is an inner cell
  4989. // columnIndex = -1, rowIndex = -1 --> current cell is reset
  4990. // columnIndex = -1, rowIndex = 2 --> Unexpected
  4991. [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  4992. private bool SetCurrentCellCore(int columnIndex, int rowIndex, bool commitEdit)
  4993. {
  4994. Debug.Assert(!(columnIndex == -1 && rowIndex > -1));
  4995. Debug.Assert(columnIndex < this.ColumnsItemsInternal.Count);
  4996. Debug.Assert(rowIndex < this.RowCount);
  4997. Debug.Assert(columnIndex == -1 || this.ColumnsItemsInternal[columnIndex].Visibility == Visibility.Visible);
  4998. Debug.Assert(!(columnIndex > -1 && rowIndex == -1)); //
  4999. if (columnIndex == this.CurrentColumnIndex &&
  5000. rowIndex == this.CurrentRowIndex)
  5001. {
  5002. Debug.Assert(this._editingColumnIndex == -1 || this._editingColumnIndex == this.CurrentColumnIndex);
  5003. Debug.Assert(this._editingRow == null || this.EditingRowIndex == this.CurrentRowIndex);
  5004. return true;
  5005. }
  5006. DataGridRow oldDisplayedCurrentRow = null;
  5007. DataGridCellCoordinates oldCurrentCell = new DataGridCellCoordinates(this.CurrentCellCoordinates);
  5008. if (this.CurrentColumnIndex > -1)
  5009. {
  5010. Debug.Assert(this.CurrentRowIndex > -1 /**/);
  5011. Debug.Assert(this.CurrentColumnIndex < this.ColumnsItemsInternal.Count);
  5012. Debug.Assert(this.CurrentRowIndex < this.RowCount);
  5013. if (!this._temporarilyResetCurrentCell)
  5014. {
  5015. bool keepFocus = this.ContainsFocus;
  5016. if (commitEdit)
  5017. {
  5018. if (!EndCellEdit(true /*commitCellEdit*/, true /*exitEditingMode*/, keepFocus))
  5019. {
  5020. return false;
  5021. }
  5022. // Resetting the current cell: setting it to (-1, -1) is not considered setting it out of bounds
  5023. if ((columnIndex != -1 && rowIndex != -1 && IsInnerCellOutOfBounds(columnIndex, rowIndex)) ||
  5024. IsInnerCellOutOfBounds(oldCurrentCell.ColumnIndex, oldCurrentCell.RowIndex))
  5025. {
  5026. return false;
  5027. }
  5028. if (oldCurrentCell.RowIndex != rowIndex && !EndRowEdit(true /*commitRowEdit*/, true /*exitEditingMode*/))
  5029. {
  5030. return false;
  5031. }
  5032. }
  5033. else
  5034. {
  5035. ExitEdit(keepFocus);
  5036. }
  5037. }
  5038. if (!IsInnerCellOutOfBounds(oldCurrentCell.ColumnIndex, oldCurrentCell.RowIndex) &&
  5039. this.DisplayData.IsRowDisplayed(oldCurrentCell.RowIndex))
  5040. {
  5041. oldDisplayedCurrentRow = this.DisplayData.GetDisplayedRow(oldCurrentCell.RowIndex);
  5042. }
  5043. }
  5044. this.CurrentColumnIndex = columnIndex;
  5045. this.CurrentRowIndex = rowIndex;
  5046. if (this._temporarilyResetCurrentCell)
  5047. {
  5048. if (columnIndex != -1)
  5049. {
  5050. this._temporarilyResetCurrentCell = false;
  5051. }
  5052. }
  5053. if (!this._temporarilyResetCurrentCell && this._editingColumnIndex != -1)
  5054. {
  5055. this._editingColumnIndex = columnIndex;
  5056. }
  5057. if (oldDisplayedCurrentRow != null)
  5058. {
  5059. if (this.AreRowHeadersVisible)
  5060. {
  5061. oldDisplayedCurrentRow.ApplyHeaderStatus(true /*animate*/);
  5062. }
  5063. DataGridCell cell = oldDisplayedCurrentRow.Cells[oldCurrentCell.ColumnIndex];
  5064. if (!(this._temporarilyResetCurrentCell && oldDisplayedCurrentRow.IsEditing && this._editingColumnIndex == cell.ColumnIndex))
  5065. {
  5066. // Don't reset the state of the current cell if we're editing it because that would put it in an invalid state
  5067. cell.ApplyCellState(true /*animate*/);
  5068. }
  5069. }
  5070. if (this.CurrentColumnIndex > -1)
  5071. {
  5072. Debug.Assert(this.CurrentRowIndex > -1 /**/);
  5073. Debug.Assert(this.CurrentColumnIndex < this.ColumnsItemsInternal.Count);
  5074. Debug.Assert(this.CurrentRowIndex < this.RowCount);
  5075. if (this.DisplayData.IsRowDisplayed(this.CurrentRowIndex))
  5076. {
  5077. DataGridRow dataGridRow = this.DisplayData.GetDisplayedRow(this.CurrentRowIndex);
  5078. dataGridRow.Cells[this.CurrentColumnIndex].ApplyCellState(true /*animate*/);
  5079. if (this.AreRowHeadersVisible)
  5080. {
  5081. dataGridRow.ApplyHeaderStatus(true /*animate*/);
  5082. }
  5083. }
  5084. }
  5085. OnCurrentCellChanged(EventArgs.Empty);
  5086. return true;
  5087. }
  5088. private void SetVerticalOffset(double newVerticalOffset)
  5089. {
  5090. _verticalOffset = newVerticalOffset;
  5091. if (_vScrollBar != null && !DoubleUtil.AreClose(newVerticalOffset, _vScrollBar.Value))
  5092. {
  5093. _vScrollBar.Value = _verticalOffset;
  5094. }
  5095. }
  5096. private void UpdateHorizontalScrollBar(bool needHorizScrollbar, bool forceHorizScrollbar, double totalVisibleWidth, double totalVisibleFrozenWidth, double cellsWidth)
  5097. {
  5098. if (this._hScrollBar != null)
  5099. {
  5100. if (needHorizScrollbar || forceHorizScrollbar)
  5101. {
  5102. // viewportSize
  5103. // v---v
  5104. //|<|_____|###|>|
  5105. // ^ ^
  5106. // min max
  5107. // we want to make the relative size of the thumb reflect the relative size of the viewing area
  5108. // viewportSize / (max + viewportSize) = cellsWidth / max
  5109. // -> viewportSize = max * cellsWidth / (max - cellsWidth)
  5110. // always zero
  5111. this._hScrollBar.Minimum = 0;
  5112. if (needHorizScrollbar)
  5113. {
  5114. // maximum travel distance -- not the total width
  5115. this._hScrollBar.Maximum = totalVisibleWidth - cellsWidth;
  5116. Debug.Assert(totalVisibleFrozenWidth >= 0);
  5117. if (this._frozenColumnScrollBarSpacer != null)
  5118. {
  5119. this._frozenColumnScrollBarSpacer.Width = totalVisibleFrozenWidth;
  5120. }
  5121. Debug.Assert(this._hScrollBar.Maximum >= 0);
  5122. // width of the scrollable viewing area
  5123. double viewPortSize = Math.Max(0, cellsWidth - totalVisibleFrozenWidth);
  5124. this._hScrollBar.ViewportSize = viewPortSize;
  5125. this._hScrollBar.LargeChange = viewPortSize;
  5126. // The ScrollBar should be in sync with HorizontalOffset at this point. There's a resize case
  5127. // where the ScrollBar will coerce an old value here, but we don't want that
  5128. if (this._hScrollBar.Value != this._horizontalOffset)
  5129. {
  5130. this._hScrollBar.Value = this._horizontalOffset;
  5131. }
  5132. }
  5133. else
  5134. {
  5135. //
  5136. this._hScrollBar.Maximum = 0;
  5137. this._hScrollBar.ViewportSize = 0;
  5138. }
  5139. if (this._hScrollBar.Visibility != Visibility.Visible)
  5140. {
  5141. // This will trigger a call to this method via Cells_SizeChanged for
  5142. this._ignoreNextScrollBarsLayout = true;
  5143. // which no processing is needed.
  5144. this._hScrollBar.Visibility = Visibility.Visible;
  5145. if (this._hScrollBar.DesiredSize.Height == 0)
  5146. {
  5147. // We need to know the height for the rest of layout to work correctly so measure it now
  5148. this._hScrollBar.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
  5149. }
  5150. }
  5151. }
  5152. else
  5153. {
  5154. this._hScrollBar.Maximum = 0;
  5155. if (this._hScrollBar.Visibility != Visibility.Collapsed)
  5156. {
  5157. // This will trigger a call to this method via Cells_SizeChanged for
  5158. // which no processing is needed.
  5159. this._hScrollBar.Visibility = Visibility.Collapsed;
  5160. this._ignoreNextScrollBarsLayout = true;
  5161. }
  5162. }
  5163. DataGridAutomationPeer peer = DataGridAutomationPeer.FromElement(this) as DataGridAutomationPeer;
  5164. if (peer != null)
  5165. {
  5166. peer.RaiseAutomationScrollEvents();
  5167. }
  5168. }
  5169. }
  5170. private void UpdateVerticalScrollBar(bool needVertScrollbar, bool forceVertScrollbar, double totalVisibleHeight, double cellsHeight)
  5171. {
  5172. if (this._vScrollBar != null)
  5173. {
  5174. if (needVertScrollbar || forceVertScrollbar)
  5175. {
  5176. // viewportSize
  5177. // v---v
  5178. //|<|_____|###|>|
  5179. // ^ ^
  5180. // min max
  5181. // we want to make the relative size of the thumb reflect the relative size of the viewing area
  5182. // viewportSize / (max + viewportSize) = cellsWidth / max
  5183. // -> viewportSize = max * cellsHeight / (totalVisibleHeight - cellsHeight)
  5184. // -> = max * cellsHeight / (totalVisibleHeight - cellsHeight)
  5185. // -> = max * cellsHeight / max
  5186. // -> = cellsHeight
  5187. // always zero
  5188. this._vScrollBar.Minimum = 0;
  5189. if (needVertScrollbar)
  5190. {
  5191. // maximum travel distance -- not the total height
  5192. this._vScrollBar.Maximum = totalVisibleHeight - cellsHeight;
  5193. Debug.Assert(this._vScrollBar.Maximum >= 0);
  5194. // total height of the display area
  5195. this._vScrollBar.ViewportSize = cellsHeight;
  5196. this._vScrollBar.LargeChange = cellsHeight;
  5197. }
  5198. else
  5199. {
  5200. //
  5201. this._vScrollBar.Maximum = 0;
  5202. this._vScrollBar.ViewportSize = 0;
  5203. }
  5204. if (this._vScrollBar.Visibility != Visibility.Visible)
  5205. {
  5206. // This will trigger a call to this method via Cells_SizeChanged for
  5207. // which no processing is needed.
  5208. this._vScrollBar.Visibility = Visibility.Visible;
  5209. if (this._vScrollBar.DesiredSize.Width == 0)
  5210. {
  5211. // We need to know the width for the rest of layout to work correctly so measure it now
  5212. this._vScrollBar.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
  5213. }
  5214. this._ignoreNextScrollBarsLayout = true;
  5215. }
  5216. }
  5217. else
  5218. {
  5219. this._vScrollBar.Maximum = 0;
  5220. if (this._vScrollBar.Visibility != Visibility.Collapsed)
  5221. {
  5222. // This will trigger a call to this method via Cells_SizeChanged for
  5223. // which no processing is needed.
  5224. this._vScrollBar.Visibility = Visibility.Collapsed;
  5225. this._ignoreNextScrollBarsLayout = true;
  5226. }
  5227. }
  5228. DataGridAutomationPeer peer = DataGridAutomationPeer.FromElement(this) as DataGridAutomationPeer;
  5229. if (peer != null)
  5230. {
  5231. peer.RaiseAutomationScrollEvents();
  5232. }
  5233. }
  5234. }
  5235. private void VerticalScrollBar_Scroll(object sender, ScrollEventArgs e)
  5236. {
  5237. ProcessVerticalScroll(e.ScrollEventType);
  5238. }
  5239. #endregion Private Methods
  5240. }
  5241. }