private void UpdateCommonStatesWithoutNeedsLayout(ManipulationUpdateKind manipulationUpdate = ManipulationUpdateKind.None) { using (InterceptSetNeedsLayout()) { UpdateCommonStates(manipulationUpdate); } }
private void UpdateCommonStates(ManipulationUpdateKind manipulationUpdate = ManipulationUpdateKind.None) { var state = GetState(IsSelected, IsPointerOver, HasPointerCapture); // On Windows, the pressed state appears only after a few, and won't appear at all if you quickly start to scroll with the finger. // So here we make sure to delay the beginning of a manipulation to match this behavior (and avoid flickering when scrolling) // We also make sure that when user taps (Enter->Pressed->Move*->Release->Exit) on the item, he is able to see the pressed (selected) state. var request = ++_goToStateRequest; TimeSpan delay; // delay to apply the 'state' bool pause; // should we force a pause after applying the 'state' if (manipulationUpdate == ManipulationUpdateKind.Clicked && _currentState != CommonStates.PressedSelected && _currentState != CommonStates.Pressed) { // When clicked (i.e. pointer released), but not yet in pressed state, we force to go immediately in pressed state // Then we let the standard go to state process (i.e. with delay handling) reach the final expected state. var pressedState = GetState(IsSelected, IsPointerOver, isPressed: true); _currentState = pressedState; VisualStateManager.GoToState(this, pressedState, true); _pauseStateUpdateUntil = DateTime.Now + MinTimeBetweenPressStates; delay = MinTimeBetweenPressStates; pause = false; } else if (manipulationUpdate == ManipulationUpdateKind.Begin) { // We delay the beginning of a manipulation to avoid flickers, but not for "exact" devices which has hover states // (i.e. mouse and pen when not on iOS) delay = MinTimeBetweenPressStates; pause = true; } else { delay = _pauseStateUpdateUntil - DateTime.Now; pause = false; } if (delay < TimeSpan.Zero) { _currentState = state; VisualStateManager.GoToState(this, state, true); } else { CoreDispatcher.Main.RunAsync(CoreDispatcherPriority.Normal, async() => { await Task.Delay(delay); if (_goToStateRequest != request) { return; } _currentState = state; VisualStateManager.GoToState(this, state, true); if (pause) { _pauseStateUpdateUntil = DateTime.Now + MinTimeBetweenPressStates; } }); } }
private void UpdateCommonStates(ManipulationUpdateKind manipulationUpdate = ManipulationUpdateKind.None) { // On Windows, the pressed state appears only after a few, and won't appear at all if you quickly start to scroll with the finger. // So here we make sure to delay the beginning of a manipulation to match this behavior (and avoid flickering when scrolling) // We also make sure that when user taps (Enter->Pressed->Move*->Release->Exit) on the item, he is able to see the pressed (selected) state. var state = GetState(IsEnabled, IsSelected, IsPointerOver, _canRaiseClickOnPointerRelease); var requestId = ++_goToStateRequest; // Request ID is use to ensure to apply only the last requested state. TimeSpan delay; // delay to apply the 'state' bool pause; // should we force a pause after applying the 'state' if (manipulationUpdate == ManipulationUpdateKind.Clicked && _currentState != CommonStates.PressedSelected && _currentState != CommonStates.Pressed) { // When clicked (i.e. pointer released), but not yet in pressed state, we force to go immediately in pressed state // Then we let the standard go to state process (i.e. with delay handling) reach the final expected state. var pressedState = GetState(IsEnabled, IsSelected, IsPointerOver, isPressed: true); _currentState = pressedState; VisualStateManager.GoToState(this, pressedState, true); _pauseStateUpdateUntil = _chronometer.Elapsed + MinTimeBetweenPressStates; delay = MinTimeBetweenPressStates; pause = false; } else if (manipulationUpdate == ManipulationUpdateKind.Begin) { // We delay the beginning of a manipulation to avoid flickers, but not for "exact" devices which has hover states // (i.e. mouse and pen when not on iOS) delay = MinTimeBetweenPressStates; pause = true; } else { delay = _pauseStateUpdateUntil - _chronometer.Elapsed; pause = false; } if (delay < TimeSpan.Zero) { _currentState = state; VisualStateManager.GoToState(this, state, true); } else { CoreDispatcher.Main.RunAsync(CoreDispatcherPriority.Normal, async() => { await Task.Delay(delay); if (_goToStateRequest != requestId // If element has been unloaded (e.g. click on a ComboBoxItem) native animations of the target state won't run. // Then even if on next load we request UpdateCommonStates, // the VSM will determine that state didn't changed and will just ignore the request. // Note: The issue is probably in the VSM to allow a GoToState while not in visual tree, // but this is the most common case and teh safest place to patch. || !IsLoaded) { return; } _currentState = state; VisualStateManager.GoToState(this, state, true); if (pause) { _pauseStateUpdateUntil = _chronometer.Elapsed + MinTimeBetweenPressStates; } }); } }