Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / DataGridHelper.cs / 1305600 / DataGridHelper.cs
//---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // //--------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Controls.Primitives; using System.Windows.Data; using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; using MS.Internal; namespace System.Windows.Controls { ////// Helper code for DataGrid. /// internal static class DataGridHelper { #region GridLines // Common code for drawing GridLines. Shared by DataGridDetailsPresenter, DataGridCellsPresenter, and Cell ////// Returns a size based on the given one with the given double subtracted out from the Width or Height. /// Used to adjust for the thickness of grid lines. /// public static Size SubtractFromSize(Size size, double thickness, bool height) { if (height) { return new Size(size.Width, Math.Max(0.0, size.Height - thickness)); } else { return new Size(Math.Max(0.0, size.Width - thickness), size.Height); } } ////// Test if either the vertical or horizontal gridlines are visible. /// public static bool IsGridLineVisible(DataGrid dataGrid, bool isHorizontal) { if (dataGrid != null) { DataGridGridLinesVisibility visibility = dataGrid.GridLinesVisibility; switch (visibility) { case DataGridGridLinesVisibility.All: return true; case DataGridGridLinesVisibility.Horizontal: return isHorizontal; case DataGridGridLinesVisibility.None: return false; case DataGridGridLinesVisibility.Vertical: return !isHorizontal; } } return false; } #endregion #region Notification Propagation public static bool ShouldNotifyCells(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.Cells); } public static bool ShouldNotifyCellsPresenter(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.CellsPresenter); } public static bool ShouldNotifyColumns(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.Columns); } public static bool ShouldNotifyColumnHeaders(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.ColumnHeaders); } public static bool ShouldNotifyColumnHeadersPresenter(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.ColumnHeadersPresenter); } public static bool ShouldNotifyColumnCollection(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.ColumnCollection); } public static bool ShouldNotifyDataGrid(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.DataGrid); } public static bool ShouldNotifyDetailsPresenter(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.DetailsPresenter); } public static bool ShouldRefreshCellContent(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.RefreshCellContent); } public static bool ShouldNotifyRowHeaders(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.RowHeaders); } public static bool ShouldNotifyRows(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.Rows); } public static bool ShouldNotifyRowSubtree(DataGridNotificationTarget target) { DataGridNotificationTarget value = DataGridNotificationTarget.Rows | DataGridNotificationTarget.RowHeaders | DataGridNotificationTarget.CellsPresenter | DataGridNotificationTarget.Cells | DataGridNotificationTarget.RefreshCellContent | DataGridNotificationTarget.DetailsPresenter; return TestTarget(target, value); } private static bool TestTarget(DataGridNotificationTarget target, DataGridNotificationTarget value) { return (target & value) != 0; } #endregion #region Tree Helpers ////// Walks up the templated parent tree looking for a parent type. /// public static T FindParent(FrameworkElement element) where T : FrameworkElement { FrameworkElement parent = element.TemplatedParent as FrameworkElement; while (parent != null) { T correctlyTyped = parent as T; if (correctlyTyped != null) { return correctlyTyped; } parent = parent.TemplatedParent as FrameworkElement; } return null; } public static T FindVisualParent (UIElement element) where T : UIElement { UIElement parent = element; while (parent != null) { T correctlyTyped = parent as T; if (correctlyTyped != null) { return correctlyTyped; } parent = VisualTreeHelper.GetParent(parent) as UIElement; } return null; } /// /// Helper method which determines if any of the elements of /// the tree is focusable and has tab stop /// public static bool TreeHasFocusAndTabStop(DependencyObject element) { if (element == null) { return false; } UIElement uielement = element as UIElement; if (uielement != null) { if (uielement.Focusable && KeyboardNavigation.GetIsTabStop(uielement)) { return true; } } else { ContentElement contentElement = element as ContentElement; if (contentElement != null && contentElement.Focusable && KeyboardNavigation.GetIsTabStop(contentElement)) { return true; } } int childCount = VisualTreeHelper.GetChildrenCount(element); for (int i = 0; i < childCount; i++) { DependencyObject child = VisualTreeHelper.GetChild(element, i) as DependencyObject; if (TreeHasFocusAndTabStop(child)) { return true; } } return false; } #endregion #region Cells Panel Helper ////// Invalidates a cell's panel if its column's width changes sufficiently. /// /// The cell or header. /// public static void OnColumnWidthChanged(IProvideDataGridColumn cell, DependencyPropertyChangedEventArgs e) { Debug.Assert((cell is DataGridCell) || (cell is DataGridColumnHeader), "provideColumn should be one of the cell or header containers."); UIElement element = (UIElement)cell; DataGridColumn column = cell.Column; bool isColumnHeader = (cell is DataGridColumnHeader); if (column != null) { // determine the desired value of width for auto kind columns DataGridLength width = column.Width; if (width.IsAuto || (!isColumnHeader && width.IsSizeToCells) || (isColumnHeader && width.IsSizeToHeader)) { DataGridLength oldWidth = (DataGridLength)e.OldValue; double desiredWidth = 0.0; if (oldWidth.UnitType != width.UnitType) { double constraintWidth = column.GetConstraintWidth(isColumnHeader); if (!DoubleUtil.AreClose(element.DesiredSize.Width, constraintWidth)) { element.InvalidateMeasure(); element.Measure(new Size(constraintWidth, double.PositiveInfinity)); } desiredWidth = element.DesiredSize.Width; } else { desiredWidth = oldWidth.DesiredValue; } if (DoubleUtil.IsNaN(width.DesiredValue) || DoubleUtil.LessThan(width.DesiredValue, desiredWidth)) { column.SetWidthInternal(new DataGridLength(width.Value, width.UnitType, desiredWidth, width.DisplayValue)); } } } } ////// Helper method which returns the clip for the cell based on whether it overlaps with frozen columns or not /// /// The cell or header. ///public static Geometry GetFrozenClipForCell(IProvideDataGridColumn cell) { DataGridCellsPanel panel = GetParentPanelForCell(cell); if (panel != null) { return panel.GetFrozenClipForChild((UIElement)cell); } return null; } /// /// Helper method which returns the parent DataGridCellsPanel for a cell /// /// The cell or header. ///Parent panel of the given cell or header public static DataGridCellsPanel GetParentPanelForCell(IProvideDataGridColumn cell) { Debug.Assert((cell is DataGridCell) || (cell is DataGridColumnHeader), "provideColumn should be one of the cell or header containers."); UIElement element = (UIElement)cell; return VisualTreeHelper.GetParent(element) as DataGridCellsPanel; } ////// Helper method which returns the parent DataGridCellPanel's offset from the scroll viewer /// for a cell or Header /// /// The cell or header. ///Parent Panel's offset with respect to scroll viewer public static double GetParentCellsPanelHorizontalOffset(IProvideDataGridColumn cell) { DataGridCellsPanel panel = GetParentPanelForCell(cell); if (panel != null) { return panel.ComputeCellsPanelHorizontalOffset(); } return 0.0; } #endregion #region Property Helpers public static bool IsDefaultValue(DependencyObject d, DependencyProperty dp) { return DependencyPropertyHelper.GetValueSource(d, dp).BaseValueSource == BaseValueSource.Default; } public static object GetCoercedTransferPropertyValue( DependencyObject baseObject, object baseValue, DependencyProperty baseProperty, DependencyObject parentObject, DependencyProperty parentProperty) { return GetCoercedTransferPropertyValue( baseObject, baseValue, baseProperty, parentObject, parentProperty, null, null); } ////// Computes the value of a given property based on the DataGrid property transfer rules. /// ////// This is intended to be called from within the coercion of the baseProperty. /// /// The target object which recieves the transferred property /// The baseValue that was passed into the coercion delegate /// The property that is being coerced /// The object that contains the parentProperty /// A property who's value should be transfered (via coercion) to the baseObject if it has a higher precedence. /// Same as parentObject but evaluated at a lower presedece for a given BaseValueSource /// Same as parentProperty but evaluated at a lower presedece for a given BaseValueSource ///public static object GetCoercedTransferPropertyValue( DependencyObject baseObject, object baseValue, DependencyProperty baseProperty, DependencyObject parentObject, DependencyProperty parentProperty, DependencyObject grandParentObject, DependencyProperty grandParentProperty) { // Transfer Property Coercion rules: // // Determine if this is a 'Transfer Property Coercion'. If so: // We can safely get the BaseValueSource because the property change originated from another // property, and thus this BaseValueSource wont be stale. // Pick a value to use based on who has the greatest BaseValueSource // If not a 'Transfer Property Coercion', simply return baseValue. This will cause a property change if the value changes, which // will trigger a 'Transfer Property Coercion', and we will no longer have a stale BaseValueSource var coercedValue = baseValue; if (IsPropertyTransferEnabled(baseObject, baseProperty)) { var propertySource = DependencyPropertyHelper.GetValueSource(baseObject, baseProperty); var maxBaseValueSource = propertySource.BaseValueSource; if (parentObject != null) { var parentPropertySource = DependencyPropertyHelper.GetValueSource(parentObject, parentProperty); if (parentPropertySource.BaseValueSource > maxBaseValueSource) { coercedValue = parentObject.GetValue(parentProperty); maxBaseValueSource = parentPropertySource.BaseValueSource; } } if (grandParentObject != null) { var grandParentPropertySource = DependencyPropertyHelper.GetValueSource(grandParentObject, grandParentProperty); if (grandParentPropertySource.BaseValueSource > maxBaseValueSource) { coercedValue = grandParentObject.GetValue(grandParentProperty); maxBaseValueSource = grandParentPropertySource.BaseValueSource; } } } return coercedValue; } /// /// Causes the given DependencyProperty to be coerced in transfer mode. /// ////// This should be called from within the target object's NotifyPropertyChanged. It MUST be called in /// response to a change in the target property. /// /// The DependencyObject which contains the property that needs to be transfered. /// The DependencyProperty that is the target of the property transfer. public static void TransferProperty(DependencyObject d, DependencyProperty p) { var transferEnabledMap = GetPropertyTransferEnabledMapForObject(d); transferEnabledMap[p] = true; d.CoerceValue(p); transferEnabledMap[p] = false; } private static DictionaryGetPropertyTransferEnabledMapForObject(DependencyObject d) { Dictionary propertyTransferEnabledForObject; if (!_propertyTransferEnabledMap.TryGetValue(d, out propertyTransferEnabledForObject)) { propertyTransferEnabledForObject = new Dictionary (); _propertyTransferEnabledMap.Add(d, propertyTransferEnabledForObject); } return propertyTransferEnabledForObject; } internal static bool IsPropertyTransferEnabled(DependencyObject d, DependencyProperty p) { Dictionary propertyTransferEnabledForObject; if ( _propertyTransferEnabledMap.TryGetValue(d, out propertyTransferEnabledForObject)) { bool isPropertyTransferEnabled; if (propertyTransferEnabledForObject.TryGetValue(p, out isPropertyTransferEnabled)) { return isPropertyTransferEnabled; } } return false; } /// /// Tracks which properties are currently being transfered. This information is needed when GetPropertyTransferEnabledMapForObject /// is called inside of Coercion. /// private static ConditionalWeakTable> _propertyTransferEnabledMap = new ConditionalWeakTable >(); #endregion #region Binding /// /// Returns true if the binding (or any part of it) is OneWay. /// internal static bool IsOneWay(BindingBase bindingBase) { if (bindingBase == null) { return false; } // If it is a standard Binding, then check if it's Mode is OneWay Binding binding = bindingBase as Binding; if (binding != null) { return binding.Mode == BindingMode.OneWay; } // A multi-binding can be OneWay as well MultiBinding multiBinding = bindingBase as MultiBinding; if (multiBinding != null) { return multiBinding.Mode == BindingMode.OneWay; } // A priority binding is a list of bindings, if any are OneWay, we'll call it OneWay PriorityBinding priBinding = bindingBase as PriorityBinding; if (priBinding != null) { CollectionsubBindings = priBinding.Bindings; int count = subBindings.Count; for (int i = 0; i < count; i++) { if (IsOneWay(subBindings[i])) { return true; } } } return false; } internal static BindingExpression GetBindingExpression(FrameworkElement element, DependencyProperty dp) { if (element != null) { return element.GetBindingExpression(dp); } return null; } internal static bool ValidateWithoutUpdate(FrameworkElement element) { bool result = true; BindingGroup bindingGroup = element.BindingGroup; DataGridCell cell = (element != null) ? element.Parent as DataGridCell : null; if (bindingGroup != null && cell != null) { Collection expressions = bindingGroup.BindingExpressions; for (int i=expressions.Count-1; i>=0; --i) { BindingExpressionBase beb = expressions[i]; if (VisualTreeHelper.IsAncestorOf(cell, beb.TargetElement, typeof(DataGridCell))) { result = beb.ValidateWithoutUpdate() && result; } } } return result; } internal static void UpdateTarget(FrameworkElement element) { BindingGroup bindingGroup = element.BindingGroup; DataGridCell cell = (element != null) ? element.Parent as DataGridCell : null; if (bindingGroup != null && cell != null) { Collection expressions = bindingGroup.BindingExpressions; for (int i=expressions.Count-1; i>=0; --i) { BindingExpressionBase beb = expressions[i]; if (VisualTreeHelper.IsAncestorOf(cell, beb.TargetElement, typeof(DataGridCell))) { beb.UpdateTarget(); } } } } internal static void SyncColumnProperty(DependencyObject column, DependencyObject content, DependencyProperty contentProperty, DependencyProperty columnProperty) { if (IsDefaultValue(column, columnProperty)) { content.ClearValue(contentProperty); } else { content.SetValue(contentProperty, column.GetValue(columnProperty)); } } internal static string GetPathFromBinding(Binding binding) { if (binding != null) { if (!string.IsNullOrEmpty(binding.XPath)) { return binding.XPath; } else if (binding.Path != null) { return binding.Path.Path; } } return null; } #endregion #region Other Helpers /// /// Method which takes in DataGridHeadersVisibility parameter /// and determines if row headers are visible. /// public static bool AreRowHeadersVisible(DataGridHeadersVisibility headersVisibility) { return (headersVisibility & DataGridHeadersVisibility.Row) == DataGridHeadersVisibility.Row; } ////// Helper method which coerces a value such that it satisfies min and max restrictions /// public static double CoerceToMinMax(double value, double minValue, double maxValue) { value = Math.Max(value, minValue); value = Math.Min(value, maxValue); return value; } ////// Helper to check if TextCompositionEventArgs.Text has any non /// escape characters. /// public static bool HasNonEscapeCharacters(TextCompositionEventArgs textArgs) { if (textArgs != null) { string text = textArgs.Text; for (int i = 0, count = text.Length; i < count; i++) { if (text[i] != _escapeChar) { return true; } } } return false; } private const char _escapeChar = '\u001b'; #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // //--------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Controls.Primitives; using System.Windows.Data; using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; using MS.Internal; namespace System.Windows.Controls { ////// Helper code for DataGrid. /// internal static class DataGridHelper { #region GridLines // Common code for drawing GridLines. Shared by DataGridDetailsPresenter, DataGridCellsPresenter, and Cell ////// Returns a size based on the given one with the given double subtracted out from the Width or Height. /// Used to adjust for the thickness of grid lines. /// public static Size SubtractFromSize(Size size, double thickness, bool height) { if (height) { return new Size(size.Width, Math.Max(0.0, size.Height - thickness)); } else { return new Size(Math.Max(0.0, size.Width - thickness), size.Height); } } ////// Test if either the vertical or horizontal gridlines are visible. /// public static bool IsGridLineVisible(DataGrid dataGrid, bool isHorizontal) { if (dataGrid != null) { DataGridGridLinesVisibility visibility = dataGrid.GridLinesVisibility; switch (visibility) { case DataGridGridLinesVisibility.All: return true; case DataGridGridLinesVisibility.Horizontal: return isHorizontal; case DataGridGridLinesVisibility.None: return false; case DataGridGridLinesVisibility.Vertical: return !isHorizontal; } } return false; } #endregion #region Notification Propagation public static bool ShouldNotifyCells(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.Cells); } public static bool ShouldNotifyCellsPresenter(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.CellsPresenter); } public static bool ShouldNotifyColumns(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.Columns); } public static bool ShouldNotifyColumnHeaders(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.ColumnHeaders); } public static bool ShouldNotifyColumnHeadersPresenter(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.ColumnHeadersPresenter); } public static bool ShouldNotifyColumnCollection(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.ColumnCollection); } public static bool ShouldNotifyDataGrid(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.DataGrid); } public static bool ShouldNotifyDetailsPresenter(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.DetailsPresenter); } public static bool ShouldRefreshCellContent(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.RefreshCellContent); } public static bool ShouldNotifyRowHeaders(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.RowHeaders); } public static bool ShouldNotifyRows(DataGridNotificationTarget target) { return TestTarget(target, DataGridNotificationTarget.Rows); } public static bool ShouldNotifyRowSubtree(DataGridNotificationTarget target) { DataGridNotificationTarget value = DataGridNotificationTarget.Rows | DataGridNotificationTarget.RowHeaders | DataGridNotificationTarget.CellsPresenter | DataGridNotificationTarget.Cells | DataGridNotificationTarget.RefreshCellContent | DataGridNotificationTarget.DetailsPresenter; return TestTarget(target, value); } private static bool TestTarget(DataGridNotificationTarget target, DataGridNotificationTarget value) { return (target & value) != 0; } #endregion #region Tree Helpers ////// Walks up the templated parent tree looking for a parent type. /// public static T FindParent(FrameworkElement element) where T : FrameworkElement { FrameworkElement parent = element.TemplatedParent as FrameworkElement; while (parent != null) { T correctlyTyped = parent as T; if (correctlyTyped != null) { return correctlyTyped; } parent = parent.TemplatedParent as FrameworkElement; } return null; } public static T FindVisualParent (UIElement element) where T : UIElement { UIElement parent = element; while (parent != null) { T correctlyTyped = parent as T; if (correctlyTyped != null) { return correctlyTyped; } parent = VisualTreeHelper.GetParent(parent) as UIElement; } return null; } /// /// Helper method which determines if any of the elements of /// the tree is focusable and has tab stop /// public static bool TreeHasFocusAndTabStop(DependencyObject element) { if (element == null) { return false; } UIElement uielement = element as UIElement; if (uielement != null) { if (uielement.Focusable && KeyboardNavigation.GetIsTabStop(uielement)) { return true; } } else { ContentElement contentElement = element as ContentElement; if (contentElement != null && contentElement.Focusable && KeyboardNavigation.GetIsTabStop(contentElement)) { return true; } } int childCount = VisualTreeHelper.GetChildrenCount(element); for (int i = 0; i < childCount; i++) { DependencyObject child = VisualTreeHelper.GetChild(element, i) as DependencyObject; if (TreeHasFocusAndTabStop(child)) { return true; } } return false; } #endregion #region Cells Panel Helper ////// Invalidates a cell's panel if its column's width changes sufficiently. /// /// The cell or header. /// public static void OnColumnWidthChanged(IProvideDataGridColumn cell, DependencyPropertyChangedEventArgs e) { Debug.Assert((cell is DataGridCell) || (cell is DataGridColumnHeader), "provideColumn should be one of the cell or header containers."); UIElement element = (UIElement)cell; DataGridColumn column = cell.Column; bool isColumnHeader = (cell is DataGridColumnHeader); if (column != null) { // determine the desired value of width for auto kind columns DataGridLength width = column.Width; if (width.IsAuto || (!isColumnHeader && width.IsSizeToCells) || (isColumnHeader && width.IsSizeToHeader)) { DataGridLength oldWidth = (DataGridLength)e.OldValue; double desiredWidth = 0.0; if (oldWidth.UnitType != width.UnitType) { double constraintWidth = column.GetConstraintWidth(isColumnHeader); if (!DoubleUtil.AreClose(element.DesiredSize.Width, constraintWidth)) { element.InvalidateMeasure(); element.Measure(new Size(constraintWidth, double.PositiveInfinity)); } desiredWidth = element.DesiredSize.Width; } else { desiredWidth = oldWidth.DesiredValue; } if (DoubleUtil.IsNaN(width.DesiredValue) || DoubleUtil.LessThan(width.DesiredValue, desiredWidth)) { column.SetWidthInternal(new DataGridLength(width.Value, width.UnitType, desiredWidth, width.DisplayValue)); } } } } ////// Helper method which returns the clip for the cell based on whether it overlaps with frozen columns or not /// /// The cell or header. ///public static Geometry GetFrozenClipForCell(IProvideDataGridColumn cell) { DataGridCellsPanel panel = GetParentPanelForCell(cell); if (panel != null) { return panel.GetFrozenClipForChild((UIElement)cell); } return null; } /// /// Helper method which returns the parent DataGridCellsPanel for a cell /// /// The cell or header. ///Parent panel of the given cell or header public static DataGridCellsPanel GetParentPanelForCell(IProvideDataGridColumn cell) { Debug.Assert((cell is DataGridCell) || (cell is DataGridColumnHeader), "provideColumn should be one of the cell or header containers."); UIElement element = (UIElement)cell; return VisualTreeHelper.GetParent(element) as DataGridCellsPanel; } ////// Helper method which returns the parent DataGridCellPanel's offset from the scroll viewer /// for a cell or Header /// /// The cell or header. ///Parent Panel's offset with respect to scroll viewer public static double GetParentCellsPanelHorizontalOffset(IProvideDataGridColumn cell) { DataGridCellsPanel panel = GetParentPanelForCell(cell); if (panel != null) { return panel.ComputeCellsPanelHorizontalOffset(); } return 0.0; } #endregion #region Property Helpers public static bool IsDefaultValue(DependencyObject d, DependencyProperty dp) { return DependencyPropertyHelper.GetValueSource(d, dp).BaseValueSource == BaseValueSource.Default; } public static object GetCoercedTransferPropertyValue( DependencyObject baseObject, object baseValue, DependencyProperty baseProperty, DependencyObject parentObject, DependencyProperty parentProperty) { return GetCoercedTransferPropertyValue( baseObject, baseValue, baseProperty, parentObject, parentProperty, null, null); } ////// Computes the value of a given property based on the DataGrid property transfer rules. /// ////// This is intended to be called from within the coercion of the baseProperty. /// /// The target object which recieves the transferred property /// The baseValue that was passed into the coercion delegate /// The property that is being coerced /// The object that contains the parentProperty /// A property who's value should be transfered (via coercion) to the baseObject if it has a higher precedence. /// Same as parentObject but evaluated at a lower presedece for a given BaseValueSource /// Same as parentProperty but evaluated at a lower presedece for a given BaseValueSource ///public static object GetCoercedTransferPropertyValue( DependencyObject baseObject, object baseValue, DependencyProperty baseProperty, DependencyObject parentObject, DependencyProperty parentProperty, DependencyObject grandParentObject, DependencyProperty grandParentProperty) { // Transfer Property Coercion rules: // // Determine if this is a 'Transfer Property Coercion'. If so: // We can safely get the BaseValueSource because the property change originated from another // property, and thus this BaseValueSource wont be stale. // Pick a value to use based on who has the greatest BaseValueSource // If not a 'Transfer Property Coercion', simply return baseValue. This will cause a property change if the value changes, which // will trigger a 'Transfer Property Coercion', and we will no longer have a stale BaseValueSource var coercedValue = baseValue; if (IsPropertyTransferEnabled(baseObject, baseProperty)) { var propertySource = DependencyPropertyHelper.GetValueSource(baseObject, baseProperty); var maxBaseValueSource = propertySource.BaseValueSource; if (parentObject != null) { var parentPropertySource = DependencyPropertyHelper.GetValueSource(parentObject, parentProperty); if (parentPropertySource.BaseValueSource > maxBaseValueSource) { coercedValue = parentObject.GetValue(parentProperty); maxBaseValueSource = parentPropertySource.BaseValueSource; } } if (grandParentObject != null) { var grandParentPropertySource = DependencyPropertyHelper.GetValueSource(grandParentObject, grandParentProperty); if (grandParentPropertySource.BaseValueSource > maxBaseValueSource) { coercedValue = grandParentObject.GetValue(grandParentProperty); maxBaseValueSource = grandParentPropertySource.BaseValueSource; } } } return coercedValue; } /// /// Causes the given DependencyProperty to be coerced in transfer mode. /// ////// This should be called from within the target object's NotifyPropertyChanged. It MUST be called in /// response to a change in the target property. /// /// The DependencyObject which contains the property that needs to be transfered. /// The DependencyProperty that is the target of the property transfer. public static void TransferProperty(DependencyObject d, DependencyProperty p) { var transferEnabledMap = GetPropertyTransferEnabledMapForObject(d); transferEnabledMap[p] = true; d.CoerceValue(p); transferEnabledMap[p] = false; } private static DictionaryGetPropertyTransferEnabledMapForObject(DependencyObject d) { Dictionary propertyTransferEnabledForObject; if (!_propertyTransferEnabledMap.TryGetValue(d, out propertyTransferEnabledForObject)) { propertyTransferEnabledForObject = new Dictionary (); _propertyTransferEnabledMap.Add(d, propertyTransferEnabledForObject); } return propertyTransferEnabledForObject; } internal static bool IsPropertyTransferEnabled(DependencyObject d, DependencyProperty p) { Dictionary propertyTransferEnabledForObject; if ( _propertyTransferEnabledMap.TryGetValue(d, out propertyTransferEnabledForObject)) { bool isPropertyTransferEnabled; if (propertyTransferEnabledForObject.TryGetValue(p, out isPropertyTransferEnabled)) { return isPropertyTransferEnabled; } } return false; } /// /// Tracks which properties are currently being transfered. This information is needed when GetPropertyTransferEnabledMapForObject /// is called inside of Coercion. /// private static ConditionalWeakTable> _propertyTransferEnabledMap = new ConditionalWeakTable >(); #endregion #region Binding /// /// Returns true if the binding (or any part of it) is OneWay. /// internal static bool IsOneWay(BindingBase bindingBase) { if (bindingBase == null) { return false; } // If it is a standard Binding, then check if it's Mode is OneWay Binding binding = bindingBase as Binding; if (binding != null) { return binding.Mode == BindingMode.OneWay; } // A multi-binding can be OneWay as well MultiBinding multiBinding = bindingBase as MultiBinding; if (multiBinding != null) { return multiBinding.Mode == BindingMode.OneWay; } // A priority binding is a list of bindings, if any are OneWay, we'll call it OneWay PriorityBinding priBinding = bindingBase as PriorityBinding; if (priBinding != null) { CollectionsubBindings = priBinding.Bindings; int count = subBindings.Count; for (int i = 0; i < count; i++) { if (IsOneWay(subBindings[i])) { return true; } } } return false; } internal static BindingExpression GetBindingExpression(FrameworkElement element, DependencyProperty dp) { if (element != null) { return element.GetBindingExpression(dp); } return null; } internal static bool ValidateWithoutUpdate(FrameworkElement element) { bool result = true; BindingGroup bindingGroup = element.BindingGroup; DataGridCell cell = (element != null) ? element.Parent as DataGridCell : null; if (bindingGroup != null && cell != null) { Collection expressions = bindingGroup.BindingExpressions; for (int i=expressions.Count-1; i>=0; --i) { BindingExpressionBase beb = expressions[i]; if (VisualTreeHelper.IsAncestorOf(cell, beb.TargetElement, typeof(DataGridCell))) { result = beb.ValidateWithoutUpdate() && result; } } } return result; } internal static void UpdateTarget(FrameworkElement element) { BindingGroup bindingGroup = element.BindingGroup; DataGridCell cell = (element != null) ? element.Parent as DataGridCell : null; if (bindingGroup != null && cell != null) { Collection expressions = bindingGroup.BindingExpressions; for (int i=expressions.Count-1; i>=0; --i) { BindingExpressionBase beb = expressions[i]; if (VisualTreeHelper.IsAncestorOf(cell, beb.TargetElement, typeof(DataGridCell))) { beb.UpdateTarget(); } } } } internal static void SyncColumnProperty(DependencyObject column, DependencyObject content, DependencyProperty contentProperty, DependencyProperty columnProperty) { if (IsDefaultValue(column, columnProperty)) { content.ClearValue(contentProperty); } else { content.SetValue(contentProperty, column.GetValue(columnProperty)); } } internal static string GetPathFromBinding(Binding binding) { if (binding != null) { if (!string.IsNullOrEmpty(binding.XPath)) { return binding.XPath; } else if (binding.Path != null) { return binding.Path.Path; } } return null; } #endregion #region Other Helpers /// /// Method which takes in DataGridHeadersVisibility parameter /// and determines if row headers are visible. /// public static bool AreRowHeadersVisible(DataGridHeadersVisibility headersVisibility) { return (headersVisibility & DataGridHeadersVisibility.Row) == DataGridHeadersVisibility.Row; } ////// Helper method which coerces a value such that it satisfies min and max restrictions /// public static double CoerceToMinMax(double value, double minValue, double maxValue) { value = Math.Max(value, minValue); value = Math.Min(value, maxValue); return value; } ////// Helper to check if TextCompositionEventArgs.Text has any non /// escape characters. /// public static bool HasNonEscapeCharacters(TextCompositionEventArgs textArgs) { if (textArgs != null) { string text = textArgs.Text; for (int i = 0, count = text.Length; i < count; i++) { if (text[i] != _escapeChar) { return true; } } } return false; } private const char _escapeChar = '\u001b'; #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- CodeConditionStatement.cs
- EmptyStringExpandableObjectConverter.cs
- RoleManagerEventArgs.cs
- DataBoundControlAdapter.cs
- SelectionItemPatternIdentifiers.cs
- DefaultPerformanceCounters.cs
- StrokeSerializer.cs
- MemberRelationshipService.cs
- HuffmanTree.cs
- DesignerVerbCollection.cs
- UpdatePanelControlTrigger.cs
- X509ChainElement.cs
- StaticDataManager.cs
- WhitespaceRuleLookup.cs
- ActivationServices.cs
- IssuedSecurityTokenParameters.cs
- TableLayoutPanelResizeGlyph.cs
- ElementFactory.cs
- XmlTypeAttribute.cs
- DataBoundControlHelper.cs
- SqlDataSourceFilteringEventArgs.cs
- SyndicationItem.cs
- StrongTypingException.cs
- TextComposition.cs
- WmlLabelAdapter.cs
- CheckBoxList.cs
- WindowVisualStateTracker.cs
- ImplicitInputBrush.cs
- Page.cs
- DataService.cs
- PreloadedPackages.cs
- XmlRawWriterWrapper.cs
- InertiaRotationBehavior.cs
- DesignTimeTemplateParser.cs
- ArithmeticException.cs
- ProfileModule.cs
- PrimarySelectionGlyph.cs
- GradientStop.cs
- BuildDependencySet.cs
- PasswordRecoveryDesigner.cs
- TouchFrameEventArgs.cs
- ConnectionStringsSection.cs
- SupportsEventValidationAttribute.cs
- BitmapMetadataBlob.cs
- SystemIPv4InterfaceProperties.cs
- AutomationElementIdentifiers.cs
- DataGridViewTextBoxColumn.cs
- ChtmlTextBoxAdapter.cs
- CompiledQuery.cs
- EntityDataSourceSelectedEventArgs.cs
- Profiler.cs
- ContextBase.cs
- ServiceDiscoveryElement.cs
- GlyphTypeface.cs
- PersonalizationState.cs
- PropertyValueUIItem.cs
- ReaderOutput.cs
- SystemIPv4InterfaceProperties.cs
- InvokeMethodActivity.cs
- DelegatedStream.cs
- ExtractedStateEntry.cs
- HtmlTitle.cs
- RoutingConfiguration.cs
- SafeWaitHandle.cs
- XPathDocumentNavigator.cs
- SkewTransform.cs
- SelectorItemAutomationPeer.cs
- SchemaTableColumn.cs
- LeftCellWrapper.cs
- XmlIlVisitor.cs
- XmlSchemaSimpleContent.cs
- CodeConstructor.cs
- TableRowCollection.cs
- Imaging.cs
- ArrayElementGridEntry.cs
- ConditionalExpression.cs
- ValueChangedEventManager.cs
- DeclarativeConditionsCollection.cs
- HttpCacheParams.cs
- infer.cs
- UserNameServiceElement.cs
- AbstractDataSvcMapFileLoader.cs
- SurrogateEncoder.cs
- SingleSelectRootGridEntry.cs
- CalculatedColumn.cs
- XamlPoint3DCollectionSerializer.cs
- CryptoProvider.cs
- HttpWriter.cs
- DataContract.cs
- MobileDeviceCapabilitiesSectionHandler.cs
- ButtonFlatAdapter.cs
- ExceptionUtil.cs
- PopupRoot.cs
- UrlRoutingModule.cs
- AsymmetricKeyExchangeDeformatter.cs
- VisualCollection.cs
- ScrollData.cs
- PrimaryKeyTypeConverter.cs
- SiteMapNodeCollection.cs
- JoinSymbol.cs