/// <summary> /// Fired when the Row is attached to the DataGrid. The scenario here is if the user is scrolling and /// the Row is a recycled container that was just added back to the visual tree. Properties that rely on a value from /// the Grid should be reevaluated because they may be stale. /// </summary> /// <remarks> /// Properties can obviously be stale if the DataGrid's value changes while the row is disconnected. They can also /// be stale for unobvious reasons. /// /// For example, the Style property is invalidated when we detect a new Visual parent. This happens for /// elements in the row (such as the RowHeader) before Prepare is called on the Row. The coercion callback /// will thus be unable to find the DataGrid and will return the wrong value. /// /// There is a potential for perf work here. If we know a DP isn't invalidated when the visual tree is reconnected /// and we know that the Grid hasn't modified that property then its value is likely fine. We could also cache whether /// or not the Grid's property is the one that's winning. If not, no need to redo the coercion. This notification /// is pretty fast already and thus not worth the work for now. /// </remarks> private void SyncProperties(bool forcePrepareCells) { // Coerce all properties on Row that depend on values from the DataGrid // Style is ok since it's equivalent to ItemContainerStyle and has already been invalidated. DataGridHelper.TransferProperty(this, BackgroundProperty); DataGridHelper.TransferProperty(this, HeaderStyleProperty); DataGridHelper.TransferProperty(this, HeaderTemplateProperty); DataGridHelper.TransferProperty(this, HeaderTemplateSelectorProperty); DataGridHelper.TransferProperty(this, ValidationErrorTemplateProperty); DataGridHelper.TransferProperty(this, DetailsTemplateProperty); DataGridHelper.TransferProperty(this, DetailsTemplateSelectorProperty); DataGridHelper.TransferProperty(this, DetailsVisibilityProperty); CoerceValue(VisibilityProperty); // Handle NewItemPlaceholder case RestoreAttachedItemValue(this, DetailsVisibilityProperty); var cellsPresenter = CellsPresenter; if (cellsPresenter != null) { cellsPresenter.SyncProperties(forcePrepareCells); RestoreAttachedItemValue(cellsPresenter, DataGridCellsPresenter.HeightProperty); } if (DetailsPresenter != null) { DetailsPresenter.SyncProperties(); } if (RowHeader != null) { RowHeader.SyncProperties(); } }
/// <summary> /// Called due to the cell's column definition changing. /// Not called due to changes within the current column definition. /// </summary> /// <remarks> /// Coerces ContentTemplate and ContentTemplateSelector. /// </remarks> /// <param name="oldColumn">The old column definition.</param> /// <param name="newColumn">The new column definition.</param> protected virtual void OnColumnChanged(DataGridColumn oldColumn, DataGridColumn newColumn) { // We need to call BuildVisualTree after changing the column (PrepareCell does this). Content = null; DataGridHelper.TransferProperty(this, StyleProperty); DataGridHelper.TransferProperty(this, IsReadOnlyProperty); }
/// <summary> /// General notification for DependencyProperty changes from the grid or from columns. /// </summary> internal void NotifyPropertyChanged(DependencyObject d, string propertyName, DependencyPropertyChangedEventArgs e, NotificationTarget target) { DataGridColumn column = d as DataGridColumn; if ((column != null) && (column != Column)) { // This notification does not apply to this cell return; } // All the notifications which are to be handled by the cell if (DataGridHelper.ShouldNotifyCells(target)) { if (e.Property == DataGridColumn.WidthProperty) { DataGridHelper.OnColumnWidthChanged(this, e); } else if (e.Property == DataGrid.CellStyleProperty || e.Property == DataGridColumn.CellStyleProperty || e.Property == StyleProperty) { DataGridHelper.TransferProperty(this, StyleProperty); } else if (e.Property == DataGrid.IsReadOnlyProperty || e.Property == DataGridColumn.IsReadOnlyProperty || e.Property == IsReadOnlyProperty) { DataGridHelper.TransferProperty(this, IsReadOnlyProperty); } else if (e.Property == DataGridColumn.DisplayIndexProperty) { TabIndex = column.DisplayIndex; } } // All the notifications which needs forward to columns if (DataGridHelper.ShouldRefreshCellContent(target)) { if (column != null && NeedsVisualTree) { if (!string.IsNullOrEmpty(propertyName)) { column.RefreshCellContent(this, propertyName); } else if (e != null && e.Property != null) { column.RefreshCellContent(this, e.Property.Name); } } } }
/// <summary> /// Prepares a cell for use. /// </summary> /// <remarks> /// Updates the column reference. /// </remarks> internal void PrepareCell(object item, DataGridRow ownerRow, int index) { Debug.Assert(_owner == null || _owner == ownerRow, "_owner should be null before PrepareCell is called or the same value as the ownerRow."); _owner = ownerRow; DataGrid dataGrid = _owner.DataGridOwner; if (dataGrid != null) { // The index of the container should correspond to the index of the column if ((index >= 0) && (index < dataGrid.Columns.Count)) { // Retrieve the column definition and pass it to the cell container DataGridColumn column = dataGrid.Columns[index]; Column = column; TabIndex = column.DisplayIndex; } if (IsEditing) { // If IsEditing was left on and this container was recycled, reset it here. // Setting this property will result in BuildVisualTree being called. IsEditing = false; } else if ((Content as FrameworkElement) == null) { // If there isn't already a visual tree, then create one. BuildVisualTree(); if (!NeedsVisualTree) { Content = item; } } // Update cell Selection bool isSelected = dataGrid.SelectedCellsInternal.Contains(this); SyncIsSelected(isSelected); } DataGridHelper.TransferProperty(this, StyleProperty); DataGridHelper.TransferProperty(this, IsReadOnlyProperty); CoerceValue(ClipProperty); }
/// <summary> /// General notification for DependencyProperty changes from the grid or from columns. /// </summary> internal void NotifyPropertyChanged(DependencyObject d, string propertyName, DependencyPropertyChangedEventArgs e, NotificationTarget target) { if (DataGridHelper.ShouldNotifyRows(target)) { if (e.Property == DataGrid.RowBackgroundProperty || e.Property == DataGrid.AlternatingRowBackgroundProperty || e.Property == BackgroundProperty || e.Property == AlternationIndexProperty) { DataGridHelper.TransferProperty(this, BackgroundProperty); } else if (e.Property == DataGrid.RowHeaderStyleProperty || e.Property == HeaderStyleProperty) { DataGridHelper.TransferProperty(this, HeaderStyleProperty); } else if (e.Property == DataGrid.RowHeaderTemplateProperty || e.Property == HeaderTemplateProperty) { DataGridHelper.TransferProperty(this, HeaderTemplateProperty); } else if (e.Property == DataGrid.RowHeaderTemplateSelectorProperty || e.Property == HeaderTemplateSelectorProperty) { DataGridHelper.TransferProperty(this, HeaderTemplateSelectorProperty); } else if (e.Property == DataGrid.RowValidationErrorTemplateProperty || e.Property == ValidationErrorTemplateProperty) { DataGridHelper.TransferProperty(this, ValidationErrorTemplateProperty); } else if (e.Property == DataGrid.RowDetailsTemplateProperty || e.Property == DetailsTemplateProperty) { DataGridHelper.TransferProperty(this, DetailsTemplateProperty); DataGridHelper.TransferProperty(this, DetailsVisibilityProperty); } else if (e.Property == DataGrid.RowDetailsTemplateSelectorProperty || e.Property == DetailsTemplateSelectorProperty) { DataGridHelper.TransferProperty(this, DetailsTemplateSelectorProperty); DataGridHelper.TransferProperty(this, DetailsVisibilityProperty); } else if (e.Property == DataGrid.RowDetailsVisibilityModeProperty || e.Property == DetailsVisibilityProperty || e.Property == IsSelectedProperty) { DataGridHelper.TransferProperty(this, DetailsVisibilityProperty); } else if (e.Property == ItemProperty) { OnItemChanged(e.OldValue, e.NewValue); } else if (e.Property == HeaderProperty) { OnHeaderChanged(e.OldValue, e.NewValue); } else if (e.Property == BindingGroupProperty) { // Re-run validation, but wait until Binding has occured. Dispatcher.BeginInvoke(new DispatcherOperationCallback(DelayedValidateWithoutUpdate), DispatcherPriority.DataBind, e.NewValue); } } if (DataGridHelper.ShouldNotifyDetailsPresenter(target)) { if (DetailsPresenter != null) { DetailsPresenter.NotifyPropertyChanged(d, e); } } if (DataGridHelper.ShouldNotifyCellsPresenter(target) || DataGridHelper.ShouldNotifyCells(target) || DataGridHelper.ShouldRefreshCellContent(target)) { DataGridCellsPresenter cellsPresenter = CellsPresenter; if (cellsPresenter != null) { cellsPresenter.NotifyPropertyChanged(d, propertyName, e, target); } } if (DataGridHelper.ShouldNotifyRowHeaders(target) && RowHeader != null) { RowHeader.NotifyPropertyChanged(d, e); } }