提交 48258a02 编写于 作者: R Rob LaDuca

Merging release/3.1 to master

...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<_PresentationBuildTasksTfm Condition="'$(MSBuildRuntimeType)' == 'Core'">netcoreapp2.1</_PresentationBuildTasksTfm> <_PresentationBuildTasksTfm Condition="'$(MSBuildRuntimeType)' == 'Core'">netcoreapp2.1</_PresentationBuildTasksTfm>
<_PresentationBuildTasksTfm Condition="'$(MSBuildRuntimeType)' != 'Core'">net472</_PresentationBuildTasksTfm> <_PresentationBuildTasksTfm Condition="'$(MSBuildRuntimeType)' != 'Core'">net472</_PresentationBuildTasksTfm>
<_PresentationBuildTasksAssembly Condition="'$(_PresentationBuildTasksAssembly)'==''">$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\tools\$(_PresentationBuildTasksTfm)\PresentationBuildTasks.dll'))</_PresentationBuildTasksAssembly> <_PresentationBuildTasksAssembly Condition="'$(_PresentationBuildTasksAssembly)'==''">$([MSBuild]::Unescape($([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\tools\$(_PresentationBuildTasksTfm)\PresentationBuildTasks.dll'))))</_PresentationBuildTasksAssembly>
</PropertyGroup> </PropertyGroup>
<UsingTask TaskName="Microsoft.Build.Tasks.Windows.MarkupCompilePass1" AssemblyFile="$(_PresentationBuildTasksAssembly)" /> <UsingTask TaskName="Microsoft.Build.Tasks.Windows.MarkupCompilePass1" AssemblyFile="$(_PresentationBuildTasksAssembly)" />
......
...@@ -83,7 +83,7 @@ internal void OnEnterParentTree() ...@@ -83,7 +83,7 @@ internal void OnEnterParentTree()
{ {
if (_sharedState == null) if (_sharedState == null)
{ {
// start with getting SharedSizeGroup value. // start with getting SharedSizeGroup value.
// this property is NOT inhereted which should result in better overall perf. // this property is NOT inhereted which should result in better overall perf.
string sharedSizeGroupId = SharedSizeGroup; string sharedSizeGroupId = SharedSizeGroup;
if (sharedSizeGroupId != null) if (sharedSizeGroupId != null)
...@@ -167,8 +167,8 @@ internal static void OnUserSizePropertyChanged(DependencyObject d, DependencyPro ...@@ -167,8 +167,8 @@ internal static void OnUserSizePropertyChanged(DependencyObject d, DependencyPro
parentGrid.Invalidate(); parentGrid.Invalidate();
} }
else else
{ {
parentGrid.InvalidateMeasure(); parentGrid.InvalidateMeasure();
} }
} }
} }
...@@ -411,6 +411,14 @@ internal double MinSizeForArrange ...@@ -411,6 +411,14 @@ internal double MinSizeForArrange
} }
} }
/// <summary>
/// Returns min size, never taking into account shared state.
/// </summary>
internal double RawMinSize
{
get { return _minSize; }
}
/// <summary> /// <summary>
/// Offset. /// Offset.
/// </summary> /// </summary>
...@@ -426,7 +434,7 @@ internal double FinalOffset ...@@ -426,7 +434,7 @@ internal double FinalOffset
internal GridLength UserSizeValueCache internal GridLength UserSizeValueCache
{ {
get get
{ {
return (GridLength) GetValue( return (GridLength) GetValue(
_isColumnDefinition ? _isColumnDefinition ?
ColumnDefinition.WidthProperty : ColumnDefinition.WidthProperty :
...@@ -442,8 +450,8 @@ internal double UserMinSizeValueCache ...@@ -442,8 +450,8 @@ internal double UserMinSizeValueCache
get get
{ {
return (double) GetValue( return (double) GetValue(
_isColumnDefinition ? _isColumnDefinition ?
ColumnDefinition.MinWidthProperty : ColumnDefinition.MinWidthProperty :
RowDefinition.MinHeightProperty); RowDefinition.MinHeightProperty);
} }
} }
...@@ -504,7 +512,7 @@ private bool CheckFlagsAnd(Flags flags) ...@@ -504,7 +512,7 @@ private bool CheckFlagsAnd(Flags flags)
private static void OnSharedSizeGroupPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) private static void OnSharedSizeGroupPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{ {
DefinitionBase definition = (DefinitionBase) d; DefinitionBase definition = (DefinitionBase) d;
if (definition.InParentLogicalTree) if (definition.InParentLogicalTree)
{ {
string sharedSizeGroupId = (string) e.NewValue; string sharedSizeGroupId = (string) e.NewValue;
...@@ -516,13 +524,13 @@ private static void OnSharedSizeGroupPropertyChanged(DependencyObject d, Depende ...@@ -516,13 +524,13 @@ private static void OnSharedSizeGroupPropertyChanged(DependencyObject d, Depende
definition._sharedState.RemoveMember(definition); definition._sharedState.RemoveMember(definition);
definition._sharedState = null; definition._sharedState = null;
} }
if ((definition._sharedState == null) && (sharedSizeGroupId != null)) if ((definition._sharedState == null) && (sharedSizeGroupId != null))
{ {
SharedSizeScope privateSharedSizeScope = definition.PrivateSharedSizeScope; SharedSizeScope privateSharedSizeScope = definition.PrivateSharedSizeScope;
if (privateSharedSizeScope != null) if (privateSharedSizeScope != null)
{ {
// if definition is not registered and both: shared size group id AND private shared scope // if definition is not registered and both: shared size group id AND private shared scope
// are available, then register definition. // are available, then register definition.
definition._sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId); definition._sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId);
definition._sharedState.AddMember(definition); definition._sharedState.AddMember(definition);
...@@ -604,7 +612,7 @@ private static void OnPrivateSharedSizeScopePropertyChanged(DependencyObject d, ...@@ -604,7 +612,7 @@ private static void OnPrivateSharedSizeScopePropertyChanged(DependencyObject d,
string sharedSizeGroup = definition.SharedSizeGroup; string sharedSizeGroup = definition.SharedSizeGroup;
if (sharedSizeGroup != null) if (sharedSizeGroup != null)
{ {
// if definition is not registered and both: shared size group id AND private shared scope // if definition is not registered and both: shared size group id AND private shared scope
// are available, then register definition. // are available, then register definition.
definition._sharedState = privateSharedSizeScope.EnsureSharedState(definition.SharedSizeGroup); definition._sharedState = privateSharedSizeScope.EnsureSharedState(definition.SharedSizeGroup);
definition._sharedState.AddMember(definition); definition._sharedState.AddMember(definition);
...@@ -670,7 +678,7 @@ private bool LayoutWasUpdated ...@@ -670,7 +678,7 @@ private bool LayoutWasUpdated
private double _offset; // offset of the DefinitionBase from left / top corner (assuming LTR case) private double _offset; // offset of the DefinitionBase from left / top corner (assuming LTR case)
private SharedSizeState _sharedState; // reference to shared state object this instance is registered with private SharedSizeState _sharedState; // reference to shared state object this instance is registered with
internal const bool ThisIsColumnDefinition = true; internal const bool ThisIsColumnDefinition = true;
internal const bool ThisIsRowDefinition = false; internal const bool ThisIsRowDefinition = false;
...@@ -872,7 +880,7 @@ private void OnLayoutUpdated(object sender, EventArgs e) ...@@ -872,7 +880,7 @@ private void OnLayoutUpdated(object sender, EventArgs e)
// accumulate min size of all participating definitions // accumulate min size of all participating definitions
for (int i = 0, count = _registry.Count; i < count; ++i) for (int i = 0, count = _registry.Count; i < count; ++i)
{ {
sharedMinSize = Math.Max(sharedMinSize, _registry[i].MinSize); sharedMinSize = Math.Max(sharedMinSize, _registry[i]._minSize);
} }
bool sharedMinSizeChanged = !DoubleUtil.AreClose(_minSize, sharedMinSize); bool sharedMinSizeChanged = !DoubleUtil.AreClose(_minSize, sharedMinSize);
...@@ -882,31 +890,65 @@ private void OnLayoutUpdated(object sender, EventArgs e) ...@@ -882,31 +890,65 @@ private void OnLayoutUpdated(object sender, EventArgs e)
{ {
DefinitionBase definitionBase = _registry[i]; DefinitionBase definitionBase = _registry[i];
if (sharedMinSizeChanged || definitionBase.LayoutWasUpdated) // we'll set d.UseSharedMinimum to maintain the invariant:
// d.UseSharedMinimum iff d._minSize < this.MinSize
// i.e. iff d is not a "long-pole" definition.
//
// Measure/Arrange of d's Grid uses d._minSize for long-pole
// definitions, and max(d._minSize, shared size) for
// short-pole definitions. This distinction allows us to react
// to changes in "long-pole-ness" more efficiently and correctly,
// by avoiding remeasures when a long-pole definition changes.
bool useSharedMinimum = !DoubleUtil.AreClose(definitionBase._minSize, sharedMinSize);
// before doing that, determine whether d's Grid needs to be remeasured.
// It's important _not_ to remeasure if the last measure is still
// valid, otherwise infinite loops are possible
bool measureIsValid;
if (!definitionBase.UseSharedMinimum)
{ {
// if definition's min size is different, then need to re-measure // d was a long-pole. measure is valid iff it's still a long-pole,
if (!DoubleUtil.AreClose(sharedMinSize, definitionBase.MinSize)) // since previous measure didn't use shared size.
{ measureIsValid = !useSharedMinimum;
Grid parentGrid = (Grid)definitionBase.Parent; }
parentGrid.InvalidateMeasure(); else if (useSharedMinimum)
definitionBase.UseSharedMinimum = true; {
} // d was a short-pole, and still is. measure is valid
else // iff the shared size didn't change
{ measureIsValid = !sharedMinSizeChanged;
definitionBase.UseSharedMinimum = false; }
else
// if measure is valid then also need to check arrange. {
// Note: definitionBase.SizeCache is volatile but at this point // d was a short-pole, but is now a long-pole. This can
// it contains up-to-date final size // happen in several ways:
if (!DoubleUtil.AreClose(sharedMinSize, definitionBase.SizeCache)) // a. d's minSize increased to or past the old shared size
{ // b. other long-pole definitions decreased, leaving
Grid parentGrid = (Grid)definitionBase.Parent; // d as the new winner
parentGrid.InvalidateArrange(); // In the former case, the measure is valid - it used
} // d's new larger minSize. In the latter case, the
} // measure is invalid - it used the old shared size,
// which is larger than d's (possibly changed) minSize
measureIsValid = (definitionBase.LayoutWasUpdated &&
DoubleUtil.GreaterThanOrClose(definitionBase._minSize, this.MinSize));
}
definitionBase.LayoutWasUpdated = false; if (!measureIsValid)
{
Grid parentGrid = (Grid)definitionBase.Parent;
parentGrid.InvalidateMeasure();
}
else if (!DoubleUtil.AreClose(sharedMinSize, definitionBase.SizeCache))
{
// if measure is valid then also need to check arrange.
// Note: definitionBase.SizeCache is volatile but at this point
// it contains up-to-date final size
Grid parentGrid = (Grid)definitionBase.Parent;
parentGrid.InvalidateArrange();
} }
// now we can restore the invariant, and clear the layout flag
definitionBase.UseSharedMinimum = useSharedMinimum;
definitionBase.LayoutWasUpdated = false;
} }
_minSize = sharedMinSize; _minSize = sharedMinSize;
...@@ -916,7 +958,7 @@ private void OnLayoutUpdated(object sender, EventArgs e) ...@@ -916,7 +958,7 @@ private void OnLayoutUpdated(object sender, EventArgs e)
_broadcastInvalidation = true; _broadcastInvalidation = true;
} }
private readonly SharedSizeScope _sharedSizeScope; // the scope this state belongs to private readonly SharedSizeScope _sharedSizeScope; // the scope this state belongs to
private readonly string _sharedSizeGroupId; // Id of the shared size group this object is servicing private readonly string _sharedSizeGroupId; // Id of the shared size group this object is servicing
private readonly List<DefinitionBase> _registry; // registry of participating definitions private readonly List<DefinitionBase> _registry; // registry of participating definitions
......
...@@ -1178,11 +1178,11 @@ private double[] CacheMinSizes(int cellsHead, bool isRows) ...@@ -1178,11 +1178,11 @@ private double[] CacheMinSizes(int cellsHead, bool isRows)
{ {
if (isRows) if (isRows)
{ {
minSizes[PrivateCells[i].RowIndex] = DefinitionsV[PrivateCells[i].RowIndex].MinSize; minSizes[PrivateCells[i].RowIndex] = DefinitionsV[PrivateCells[i].RowIndex].RawMinSize;
} }
else else
{ {
minSizes[PrivateCells[i].ColumnIndex] = DefinitionsU[PrivateCells[i].ColumnIndex].MinSize; minSizes[PrivateCells[i].ColumnIndex] = DefinitionsU[PrivateCells[i].ColumnIndex].RawMinSize;
} }
i = PrivateCells[i].Next; i = PrivateCells[i].Next;
......
...@@ -60,7 +60,7 @@ public ItemsControl() : base() ...@@ -60,7 +60,7 @@ public ItemsControl() : base()
static ItemsControl() static ItemsControl()
{ {
// Define default style in code instead of in theme files. // Define default style in code instead of in theme files.
DefaultStyleKeyProperty.OverrideMetadata(typeof(ItemsControl), new FrameworkPropertyMetadata(typeof(ItemsControl))); DefaultStyleKeyProperty.OverrideMetadata(typeof(ItemsControl), new FrameworkPropertyMetadata(typeof(ItemsControl)));
_dType = DependencyObjectType.FromSystemTypeInternal(typeof(ItemsControl)); _dType = DependencyObjectType.FromSystemTypeInternal(typeof(ItemsControl));
EventManager.RegisterClassHandler(typeof(ItemsControl), Keyboard.GotKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(OnGotFocus)); EventManager.RegisterClassHandler(typeof(ItemsControl), Keyboard.GotKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(OnGotFocus));
...@@ -3011,7 +3011,7 @@ private bool IsOnCurrentPage(FrameworkElement viewPort, FrameworkElement element ...@@ -3011,7 +3011,7 @@ private bool IsOnCurrentPage(FrameworkElement viewPort, FrameworkElement element
Rect viewPortBounds = new Rect(new Point(), viewPort.RenderSize); Rect viewPortBounds = new Rect(new Point(), viewPort.RenderSize);
Rect elementBounds = new Rect(new Point(), element.RenderSize); Rect elementBounds = new Rect(new Point(), element.RenderSize);
elementBounds = element.TransformToAncestor(viewPort).TransformBounds(elementBounds); elementBounds = CorrectCatastrophicCancellation(element.TransformToAncestor(viewPort)).TransformBounds(elementBounds);
bool northSouth = (axis == FocusNavigationDirection.Up || axis == FocusNavigationDirection.Down); bool northSouth = (axis == FocusNavigationDirection.Up || axis == FocusNavigationDirection.Down);
bool eastWest = (axis == FocusNavigationDirection.Left || axis == FocusNavigationDirection.Right); bool eastWest = (axis == FocusNavigationDirection.Left || axis == FocusNavigationDirection.Right);
...@@ -3078,6 +3078,46 @@ private bool IsOnCurrentPage(FrameworkElement viewPort, FrameworkElement element ...@@ -3078,6 +3078,46 @@ private bool IsOnCurrentPage(FrameworkElement viewPort, FrameworkElement element
return ElementViewportPosition.None; return ElementViewportPosition.None;
} }
// in large virtualized hierarchical lists (TreeView or grouping), the transform
// returned by element.TransformToAncestor(viewport) is vulnerable to catastrophic
// cancellation. If element is at the top of the viewport, but embedded in
// layers of the hierarchy, the contributions of the intermediate elements add
// up to a large positive number which should exactly cancel out the large
// negative offset of the viewport's direct child to produce net offset of 0.0.
// But floating-point drift while accumulating the intermediate offsets and
// catastrophic cancellation in the last step may produce a very small
// non-zero number instead (e.g. -0.0000000000006548). This can lead to
// infinite loops and incorrect decisions in layout.
// To mitigate this problem, replace near-zero offsets with zero.
private static GeneralTransform CorrectCatastrophicCancellation(GeneralTransform transform)
{
MatrixTransform matrixTransform = transform as MatrixTransform;
if (matrixTransform != null)
{
bool needNewTransform = false;
Matrix matrix = matrixTransform.Matrix;
if (matrix.OffsetX != 0.0 && LayoutDoubleUtil.AreClose(matrix.OffsetX, 0.0))
{
matrix.OffsetX = 0.0;
needNewTransform = true;
}
if (matrix.OffsetY != 0.0 && LayoutDoubleUtil.AreClose(matrix.OffsetY, 0.0))
{
matrix.OffsetY = 0.0;
needNewTransform = true;
}
if (needNewTransform)
{
transform = new MatrixTransform(matrix);
}
}
return transform;
}
private static bool ElementIntersectsViewport(Rect viewportRect, Rect elementRect) private static bool ElementIntersectsViewport(Rect viewportRect, Rect elementRect)
{ {
if (viewportRect.IsEmpty || elementRect.IsEmpty) if (viewportRect.IsEmpty || elementRect.IsEmpty)
......
...@@ -1237,7 +1237,7 @@ private void ClearAnchorInformation(bool shouldAbort) ...@@ -1237,7 +1237,7 @@ private void ClearAnchorInformation(bool shouldAbort)
// don't delve into non-VSP panels - the result is // don't delve into non-VSP panels - the result is
// inconsistent with FindScrollOffset, and causes // inconsistent with FindScrollOffset, and causes
// infinite loops // infinite loops
innerPanel = innerPanel as VirtualizingStackPanel; innerPanel = innerPanel as VirtualizingStackPanel;
if (innerPanel != null && innerPanel.IsVisible) if (innerPanel != null && innerPanel.IsVisible)
...@@ -2279,7 +2279,7 @@ private Size RealMeasureOverride(Size constraint) ...@@ -2279,7 +2279,7 @@ private Size RealMeasureOverride(Size constraint)
// final size (e.g. when content arrives via bindings // final size (e.g. when content arrives via bindings
// that don't activate until after layout), as it // that don't activate until after layout), as it
// causes a lot of extra measure passes, where "a lot" // causes a lot of extra measure passes, where "a lot"
// can be as bad as "infinite". // can be as bad as "infinite".
// //
// To avoid this waste, exclude a proportional part // To avoid this waste, exclude a proportional part
// of the normal viewport as well. // of the normal viewport as well.
...@@ -2812,7 +2812,7 @@ private Size RealMeasureOverride(Size constraint) ...@@ -2812,7 +2812,7 @@ private Size RealMeasureOverride(Size constraint)
// If there were a collection changed between the BringIndexIntoView call // If there were a collection changed between the BringIndexIntoView call
// and the current Measure then it is possible that the item for the // and the current Measure then it is possible that the item for the
// _bringIntoViewContainer has been removed from the collection and so // _bringIntoViewContainer has been removed from the collection and so
// has the container. We need to guard against this scenario. // has the container. We need to guard against this scenario.
_bringIntoViewContainer = null; _bringIntoViewContainer = null;
} }
else else
...@@ -4609,7 +4609,7 @@ private void ClearIsScrollActive() ...@@ -4609,7 +4609,7 @@ private void ClearIsScrollActive()
// if the viewport is empty in the scrolling direction, force the // if the viewport is empty in the scrolling direction, force the
// cache to be empty also. This avoids an infinite loop re- and // cache to be empty also. This avoids an infinite loop re- and
// de-virtualizing the last item // de-virtualizing the last item
if (IsViewportEmpty(isHorizontal, viewport)) if (IsViewportEmpty(isHorizontal, viewport))
{ {
cacheLength = new VirtualizationCacheLength(0, 0); cacheLength = new VirtualizationCacheLength(0, 0);
...@@ -5550,7 +5550,7 @@ private void CoerceScrollingViewportOffset(ref Rect viewport, Size extent, bool ...@@ -5550,7 +5550,7 @@ private void CoerceScrollingViewportOffset(ref Rect viewport, Size extent, bool
bool areContainersUniformlySized, bool areContainersUniformlySized,
double uniformOrAverageContainerSize) double uniformOrAverageContainerSize)
{ {
if (firstContainer == null) if (firstContainer == null || IsViewportEmpty(isHorizontal, viewport))
{ {
return -1.0; // undefined if no children in view return -1.0; // undefined if no children in view
} }
...@@ -6149,7 +6149,7 @@ private void CoerceScrollingViewportOffset(ref Rect viewport, Size extent, bool ...@@ -6149,7 +6149,7 @@ private void CoerceScrollingViewportOffset(ref Rect viewport, Size extent, bool
// into non-uniform mode just because the pixel heights are different, // into non-uniform mode just because the pixel heights are different,
// and a good reason to avoid it: it requires looping through all // and a good reason to avoid it: it requires looping through all
// containers to compute an average size, which breaks third-party's // containers to compute an average size, which breaks third-party's
// attempts to do data virtualization // attempts to do data virtualization
bool ignoreContainerPixelSize = IsPixelBased || (IsScrolling && !hasVirtualizingChildren); bool ignoreContainerPixelSize = IsPixelBased || (IsScrolling && !hasVirtualizingChildren);
if (isHorizontal) if (isHorizontal)
...@@ -9526,7 +9526,7 @@ private void OnScrollChange() ...@@ -9526,7 +9526,7 @@ private void OnScrollChange()
// //
// We do not want the cache measure pass to affect the visibility // We do not want the cache measure pass to affect the visibility
// of the scrollbars because this makes bad user experience and // of the scrollbars because this makes bad user experience and
// is also the source of scrolling bugs. // is also the source of scrolling bugs.
// //
stackPixelSize.Width = _scrollData._extent.Width; stackPixelSize.Width = _scrollData._extent.Width;
...@@ -9641,7 +9641,7 @@ private void OnScrollChange() ...@@ -9641,7 +9641,7 @@ private void OnScrollChange()
offsetForScrollViewerRemeasure.X = newOffset; offsetForScrollViewerRemeasure.X = newOffset;
// adjust the persisted viewports too, in case the next use // adjust the persisted viewports too, in case the next use
// occurs before a measure, e.g. adding item to Items // occurs before a measure, e.g. adding item to Items
_viewport.X = newOffset; _viewport.X = newOffset;
_extendedViewport.X += delta; _extendedViewport.X += delta;
...@@ -9666,7 +9666,7 @@ private void OnScrollChange() ...@@ -9666,7 +9666,7 @@ private void OnScrollChange()
offsetForScrollViewerRemeasure.Y = newOffset; offsetForScrollViewerRemeasure.Y = newOffset;
// adjust the persisted viewports too, in case the next use // adjust the persisted viewports too, in case the next use
// occurs before a measure, e.g. adding item to Items // occurs before a measure, e.g. adding item to Items
_viewport.Y = newOffset; _viewport.Y = newOffset;
_extendedViewport.Y += delta; _extendedViewport.Y += delta;
......
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
#if RIBBON_IN_FRAMEWORK #if RIBBON_IN_FRAMEWORK
namespace System.Windows.Controls.Ribbon namespace System.Windows.Controls.Ribbon
...@@ -1059,7 +1059,11 @@ public static bool IsOurWindow(IntPtr hwnd, DependencyObject element) ...@@ -1059,7 +1059,11 @@ public static bool IsOurWindow(IntPtr hwnd, DependencyObject element)
// popups when both active source and current captured is // popups when both active source and current captured is
// null due to clicking some where else should be handled by // null due to clicking some where else should be handled by
// click through event handler. // click through event handler.
ReacquireCapture(targetCapture, targetFocus); if (!ReacquireCapture(targetCapture, targetFocus))
{
// call the setter if we couldn't reacquire capture
setter(false);
}
e.Handled = true; e.Handled = true;
} }
else else
...@@ -1078,7 +1082,11 @@ public static bool IsOurWindow(IntPtr hwnd, DependencyObject element) ...@@ -1078,7 +1082,11 @@ public static bool IsOurWindow(IntPtr hwnd, DependencyObject element)
{ {
// If a descendant of targetCapture is losing capture // If a descendant of targetCapture is losing capture
// then take capture on targetCapture // then take capture on targetCapture
ReacquireCapture(targetCapture, targetFocus); if (!ReacquireCapture(targetCapture, targetFocus))
{
// call the setter if we couldn't reacquire capture
setter(false);
}
e.Handled = true; e.Handled = true;
} }
else if (!IsCaptureInSubtree(targetCapture)) else if (!IsCaptureInSubtree(targetCapture))
...@@ -1092,13 +1100,14 @@ public static bool IsOurWindow(IntPtr hwnd, DependencyObject element) ...@@ -1092,13 +1100,14 @@ public static bool IsOurWindow(IntPtr hwnd, DependencyObject element)
} }
} }
private static void ReacquireCapture(UIElement targetCapture, UIElement targetFocus) private static bool ReacquireCapture(UIElement targetCapture, UIElement targetFocus)
{ {
Mouse.Capture(targetCapture, CaptureMode.SubTree); bool success = Mouse.Capture(targetCapture, CaptureMode.SubTree);
if (targetFocus != null && !targetFocus.IsKeyboardFocusWithin) if (success && targetFocus != null && !targetFocus.IsKeyboardFocusWithin)
{ {
targetFocus.Focus(); targetFocus.Focus();
} }
return success;
} }
public static bool IsMousePhysicallyOver(UIElement element) public static bool IsMousePhysicallyOver(UIElement element)
......
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
#if RIBBON_IN_FRAMEWORK #if RIBBON_IN_FRAMEWORK
namespace System.Windows.Controls.Ribbon namespace System.Windows.Controls.Ribbon
...@@ -30,11 +30,11 @@ namespace Microsoft.Windows.Controls.Ribbon ...@@ -30,11 +30,11 @@ namespace Microsoft.Windows.Controls.Ribbon
using Microsoft.Windows.Controls.Ribbon.Primitives; using Microsoft.Windows.Controls.Ribbon.Primitives;
#endif #endif
using MS.Internal; using MS.Internal;
#endregion #endregion
/// <summary> /// <summary>
/// RibbonMenuButton is an ItemsControl which on clicking displays a Menu. Its Items could be either RibbonMenuItems, RibbonGallerys or Separators. /// RibbonMenuButton is an ItemsControl which on clicking displays a Menu. Its Items could be either RibbonMenuItems, RibbonGallerys or Separators.
/// </summary> /// </summary>
[TemplatePart(Name = RibbonMenuButton.ResizeThumbTemplatePartName, Type = typeof(Thumb))] [TemplatePart(Name = RibbonMenuButton.ResizeThumbTemplatePartName, Type = typeof(Thumb))]
[TemplatePart(Name = RibbonMenuButton.ToggleButtonTemplatePartName, Type = typeof(RibbonToggleButton))] [TemplatePart(Name = RibbonMenuButton.ToggleButtonTemplatePartName, Type = typeof(RibbonToggleButton))]
...@@ -592,9 +592,9 @@ protected override void ClearContainerForItemOverride(DependencyObject element, ...@@ -592,9 +592,9 @@ protected override void ClearContainerForItemOverride(DependencyObject element,
{ {
base.ClearContainerForItemOverride(element, item); base.ClearContainerForItemOverride(element, item);
// RibbonComboBox containers are pre-generated. // RibbonComboBox containers are pre-generated.
// When dropdown is opened for the first time ever and ItemContainerGenerator // When dropdown is opened for the first time ever and ItemContainerGenerator
// is hooked up to ItemsPanel, existing containers are cleared, causing _galleryCount to be -ve. // is hooked up to ItemsPanel, existing containers are cleared, causing _galleryCount to be -ve.
// Hence the check for _galleryCount > 0 // Hence the check for _galleryCount > 0
if (element is RibbonGallery && _galleryCount > 0) if (element is RibbonGallery && _galleryCount > 0)
{ {
...@@ -672,7 +672,7 @@ protected override bool HandlesScrolling ...@@ -672,7 +672,7 @@ protected override bool HandlesScrolling
public override void OnApplyTemplate() public override void OnApplyTemplate()
{ {
// If a new template has just been generated then // If a new template has just been generated then
// be sure to clear any stale ItemsHost references // be sure to clear any stale ItemsHost references
if (InternalItemsHost != null && !this.IsAncestorOf(InternalItemsHost)) if (InternalItemsHost != null && !this.IsAncestorOf(InternalItemsHost))
{ {
...@@ -824,7 +824,7 @@ internal void OnNavigationKeyDown(KeyEventArgs e) ...@@ -824,7 +824,7 @@ internal void OnNavigationKeyDown(KeyEventArgs e)
{ {
if (itemNavigateFromCurrentFocused) if (itemNavigateFromCurrentFocused)
{ {
// event could have bubbled up from MenuItem // event could have bubbled up from MenuItem
// when it could not navigate to the next item (for eg. gallery) // when it could not navigate to the next item (for eg. gallery)
handled = RibbonHelper.NavigateToNextMenuItemOrGallery(this, focusedIndex, BringIndexIntoView); handled = RibbonHelper.NavigateToNextMenuItemOrGallery(this, focusedIndex, BringIndexIntoView);
} }
...@@ -841,7 +841,7 @@ internal void OnNavigationKeyDown(KeyEventArgs e) ...@@ -841,7 +841,7 @@ internal void OnNavigationKeyDown(KeyEventArgs e)
{ {
if (itemNavigateFromCurrentFocused) if (itemNavigateFromCurrentFocused)
{ {
// event could have bubbled up from MenuItem // event could have bubbled up from MenuItem
// when it could not navigate to the previous item (for eg. gallery) // when it could not navigate to the previous item (for eg. gallery)
handled = RibbonHelper.NavigateToPreviousMenuItemOrGallery(this, focusedIndex, BringIndexIntoView); handled = RibbonHelper.NavigateToPreviousMenuItemOrGallery(this, focusedIndex, BringIndexIntoView);
} }
...@@ -1015,7 +1015,7 @@ void OnPopupResize(object sender, DragDeltaEventArgs e) ...@@ -1015,7 +1015,7 @@ void OnPopupResize(object sender, DragDeltaEventArgs e)
} }
/// <summary> /// <summary>
/// Called from UIA Peers. /// Called from UIA Peers.
/// </summary> /// </summary>
/// <param name="newWidth"></param> /// <param name="newWidth"></param>
/// <param name="newHeight"></param> /// <param name="newHeight"></param>
...@@ -1079,11 +1079,11 @@ private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyProper ...@@ -1079,11 +1079,11 @@ private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyProper
internal virtual void OnIsDropDownOpenChanged(DependencyPropertyChangedEventArgs e) internal virtual void OnIsDropDownOpenChanged(DependencyPropertyChangedEventArgs e)
{ {
// If the drop down is closed due to // If the drop down is closed due to
// an action of context menu or if the // an action of context menu or if the
// ContextMenu for a parent (Ribbon) // ContextMenu for a parent (Ribbon)
// was opened by right clicking this // was opened by right clicking this
// RibbonMenuButton (RibbonApplicationMenu) // RibbonMenuButton (RibbonApplicationMenu)
// then ContextMenuClosed event is never raised. // then ContextMenuClosed event is never raised.
// Hence reset the flag. // Hence reset the flag.
InContextMenu = false; InContextMenu = false;
...@@ -1098,7 +1098,7 @@ internal virtual void OnIsDropDownOpenChanged(DependencyPropertyChangedEventArgs ...@@ -1098,7 +1098,7 @@ internal virtual void OnIsDropDownOpenChanged(DependencyPropertyChangedEventArgs
BaseOnIsKeyboardFocusWithin(); BaseOnIsKeyboardFocusWithin();
OnDropDownOpened(EventArgs.Empty); OnDropDownOpened(EventArgs.Empty);
// Clear local values // Clear local values
// so that when DropDown opens it shows in it original size and PlacementMode // so that when DropDown opens it shows in it original size and PlacementMode
RibbonDropDownHelper.ClearLocalValues(_itemsPresenter, _popup); RibbonDropDownHelper.ClearLocalValues(_itemsPresenter, _popup);
...@@ -1110,7 +1110,7 @@ internal virtual void OnIsDropDownOpenChanged(DependencyPropertyChangedEventArgs ...@@ -1110,7 +1110,7 @@ internal virtual void OnIsDropDownOpenChanged(DependencyPropertyChangedEventArgs
} }
// IsDropDownPositionedAbove is updated asynchronously. // IsDropDownPositionedAbove is updated asynchronously.
// As a result the resize thumb would change position and we could see a visual artifact of this change after Popup opens. // As a result the resize thumb would change position and we could see a visual artifact of this change after Popup opens.
Dispatcher.BeginInvoke(new DispatcherOperationCallback(UpdateDropDownPosition), DispatcherPriority.Loaded, new object[] { null }); Dispatcher.BeginInvoke(new DispatcherOperationCallback(UpdateDropDownPosition), DispatcherPriority.Loaded, new object[] { null });
} }
else else
...@@ -1200,15 +1200,15 @@ private static void OnHasGalleryChanged(DependencyObject d, DependencyPropertyCh ...@@ -1200,15 +1200,15 @@ private static void OnHasGalleryChanged(DependencyObject d, DependencyPropertyCh
RibbonHelper.SetDropDownHeight(menuButton._itemsPresenter, (bool)e.NewValue, menuButton.DropDownHeight); RibbonHelper.SetDropDownHeight(menuButton._itemsPresenter, (bool)e.NewValue, menuButton.DropDownHeight);
} }
// Note that when the HasGallery property changes we expect that the // Note that when the HasGallery property changes we expect that the
// VerticalScrollBarVisibilityProperty for the primary _submenuScrollViewer // VerticalScrollBarVisibilityProperty for the primary _submenuScrollViewer
// that hosts galleries and/or menu items is updated. Even though this // that hosts galleries and/or menu items is updated. Even though this
// property is marked AffectsMeasure it doesn't exactly cause the additonal // property is marked AffectsMeasure it doesn't exactly cause the additonal
// call to ScrollViewer.MeasureOverrider because HasGallery is typically // call to ScrollViewer.MeasureOverrider because HasGallery is typically
// updated during a Measure pass when PrepareContainerForItemOverride is // updated during a Measure pass when PrepareContainerForItemOverride is
// called and thus the invalidation noops. To ensure that we call // called and thus the invalidation noops. To ensure that we call
// ScrollViewer.MeasureOverride another time after this property has been // ScrollViewer.MeasureOverride another time after this property has been
// updated, we need to wait for the current Measure pass to subside and // updated, we need to wait for the current Measure pass to subside and
// then InvalidateMeasure on the _submenuScrollViewer. // then InvalidateMeasure on the _submenuScrollViewer.
RibbonHelper.InvalidateScrollBarVisibility(menuButton._submenuScrollViewer); RibbonHelper.InvalidateScrollBarVisibility(menuButton._submenuScrollViewer);
...@@ -1281,7 +1281,7 @@ private object UpdateDropDownPosition(object arg) ...@@ -1281,7 +1281,7 @@ private object UpdateDropDownPosition(object arg)
// Cache the screen bounds of the monitor in which the dropdown is opened // Cache the screen bounds of the monitor in which the dropdown is opened
_screenBounds = RibbonDropDownHelper.GetScreenBounds(_itemsPresenter, _popup); _screenBounds = RibbonDropDownHelper.GetScreenBounds(_itemsPresenter, _popup);
// Also cache the PopupRoot if opened for the first time // Also cache the PopupRoot if opened for the first time
if (_popupRoot == null && _itemsPresenter != null) if (_popupRoot == null && _itemsPresenter != null)
{ {
...@@ -1394,7 +1394,7 @@ internal RibbonToggleButton PartToggleButton ...@@ -1394,7 +1394,7 @@ internal RibbonToggleButton PartToggleButton
} }
/// <summary> /// <summary>
/// base exits MenuMode on any Mouse clicks. We want to prevent that. /// base exits MenuMode on any Mouse clicks. We want to prevent that.
/// </summary> /// </summary>
/// <param name="e"></param> /// <param name="e"></param>
protected override void HandleMouseButton(MouseButtonEventArgs e) protected override void HandleMouseButton(MouseButtonEventArgs e)
...@@ -1471,9 +1471,9 @@ protected override void OnPreviewMouseDown(MouseButtonEventArgs e) ...@@ -1471,9 +1471,9 @@ protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e) protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e)
{ {
// If IsKeyboardFocusWithin has become true, then do not // If IsKeyboardFocusWithin has become true, then do not
// call base.OnIsKeyboardFocusWithinChanged right away. // call base.OnIsKeyboardFocusWithinChanged right away.
// Defer the bases call until DropDown gets opened or // Defer the bases call until DropDown gets opened or
// one of the descendants get focus. // one of the descendants get focus.
if (!IsKeyboardFocusWithin) if (!IsKeyboardFocusWithin)
{ {
...@@ -1513,7 +1513,10 @@ private void OnGotKeyboardFocusThunk(KeyboardFocusChangedEventArgs e) ...@@ -1513,7 +1513,10 @@ private void OnGotKeyboardFocusThunk(KeyboardFocusChangedEventArgs e)
{ {
// Call base.OnIsKeyboardFocusWithinChanged only if the new focus // Call base.OnIsKeyboardFocusWithinChanged only if the new focus
// is not a direct descendant of menu button. // is not a direct descendant of menu button.
// It's possible to get here when disabled, which can lead to a
// focus war resulting in StackOverflow. Don't start the war.
if (e.OriginalSource != this && if (e.OriginalSource != this &&
this.IsEnabled &&
!TreeHelper.IsVisualAncestorOf(this, e.OriginalSource as DependencyObject)) !TreeHelper.IsVisualAncestorOf(this, e.OriginalSource as DependencyObject))
{ {
BaseOnIsKeyboardFocusWithin(); BaseOnIsKeyboardFocusWithin();
...@@ -1528,13 +1531,19 @@ protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) ...@@ -1528,13 +1531,19 @@ protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
if (ribbonCurrentSelection != null && if (ribbonCurrentSelection != null &&
IsDropDownOpen) IsDropDownOpen)
{ {
// If the drop down is open and the ribbonCurrentSelection is valid
// but still popup doesnt have focus within,
// then focus the current selection.
// It's possible to get here when disabled, or when an app explicitly
// moves focus in a GotKeyboardFocus handler called earlier in the
// bubbling route. Either of these can lead to a
// focus war resulting in StackOverflow. Don't start the war
UIElement popupChild = _popup.TryGetChild(); UIElement popupChild = _popup.TryGetChild();
if (popupChild != null && if (popupChild != null &&
this.IsEnabled &&
this.IsKeyboardFocusWithin &&
!popupChild.IsKeyboardFocusWithin) !popupChild.IsKeyboardFocusWithin)
{ {
// If the drop down is open and the ribbonCurrentSelection is valid
// but still popup doesnt have focus within,
// then focus the current selection.
ribbonCurrentSelection.Focus(); ribbonCurrentSelection.Focus();
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册