diff --git a/src/Uno.UI/DirectUI/ElevationHelper.cs b/src/Uno.UI/DirectUI/ElevationHelper.cs
new file mode 100644
index 000000000000..6dad374409dd
--- /dev/null
+++ b/src/Uno.UI/DirectUI/ElevationHelper.cs
@@ -0,0 +1,58 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+// MUX Reference dxaml\phone\lib\ElevationHelper.cpp, tag winui3/release/1.5.4, commit 98a60c8
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Media;
+
+namespace DirectUI;
+
+internal static class ElevationHelper
+{
+ //// The initial Z offset applied to all elevated controls
+ //private const float s_elevationBaseDepth = 32.0f;
+ //// This additional Z offset will be applied for each tier of logically parented controls
+ //private const float s_elevationIterativeDepth = 8.0f;
+
+ //internal static void ApplyThemeShadow(UIElement target)
+ //{
+ // var themeShadow = new ThemeShadow();
+ // target.Shadow = themeShadow;
+ //}
+
+ //internal static void ApplyElevationEffect(UIElement target, int depth)
+ //{
+ // // Calculate the Z offset based on the depth of the shadow
+ // var calculatedZDepth = s_elevationBaseDepth + (depth * s_elevationIterativeDepth);
+
+ // var endTranslation = new Vector3(0.0f, 0.0f, calculatedZDepth);
+
+ // // Apply a translation facade value
+ // target.Translation = endTranslation;
+
+ // // Apply a shadow to the element
+ // ApplyThemeShadow(target);
+ //}
+
+ // Move the control forward in Z and apply a shadow effect to it.
+ // If the control is part of a tier of elevated controls (for example a MenuFlyoutSubItem),
+ // you may provide an additional "depth" value that provides an additional Z offset.
+ internal static void ApplyElevationEffect(UIElement target, int depth = 0, int? baseElevation = null)
+ {
+ }
+
+ // Remove any shadow applied with ApplyElevationEffect
+ internal static void ClearElevationEffect(UIElement target)
+ {
+ }
+
+ // Checks if the "IsDefaultShadowEnabled" resource is defined as True or not, determining
+ // if a control should enable a shadow by default.
+ internal static bool IsDefaultShadowEnabled(FrameworkElement resourceTarget) => false;
+}
diff --git a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.Properties.cs b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.Properties.cs
index d6826020cde6..962769faaa31 100644
--- a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.Properties.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.Properties.cs
@@ -208,11 +208,6 @@ public Style TextBoxStyle
typeof(ComboBox),
new FrameworkPropertyMetadata(null));
- ///
- /// Occurs when the user submits some text that does not correspond to an item in the ComboBox dropdown list.
- ///
- public event TypedEventHandler TextSubmitted;
-
///
/// Occurs when the drop-down portion of the ComboBox closes.
///
@@ -222,4 +217,9 @@ public Style TextBoxStyle
/// Occurs when the drop-down portion of the ComboBox opens.
///
public event EventHandler DropDownOpened;
+
+ ///
+ /// Occurs when the user submits some text that does not correspond to an item in the ComboBox dropdown list.
+ ///
+ public event TypedEventHandler TextSubmitted;
}
diff --git a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.custom.cs b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.custom.cs
index ed510ce04b7c..972ec4db2cc8 100644
--- a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.custom.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.custom.cs
@@ -863,6 +863,8 @@ Point getChildLocation()
#endif
child.Arrange(frame);
+
+ combo.m_bPopupHasBeenArrangedOnce = true;
}
}
}
diff --git a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.h.mux.cs b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.h.mux.cs
index f6ae88846714..cebba3e7d777 100644
--- a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.h.mux.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.h.mux.cs
@@ -4,6 +4,7 @@
using System.Text;
using System.Threading.Tasks;
using Microsoft.UI.Xaml.Documents;
+using Microsoft.UI.Xaml.Media.Animation;
using Uno.Disposables;
using Uno.UI.Xaml.Input;
using Windows.Foundation;
@@ -12,10 +13,18 @@ namespace Microsoft.UI.Xaml.Controls;
partial class ComboBox
{
+#pragma warning disable CS0067 // Unused only in reference API.
+#pragma warning disable CS0649 // Unused only in reference API.
+#pragma warning disable CS0169 // Unused only in reference API.
+#pragma warning disable CS0168 // Unused only in reference API.
+#pragma warning disable CS0414 // Unused only in reference API.
internal bool IsSearchResultIndexSet() => m_searchResultIndexSet;
internal int GetSearchResultIndex() => m_searchResultIndex;
+ private bool m_bIsPopupPannable;
+ private bool m_bShouldCarousel;
+ private bool m_bShouldCenterSelectedItem;
private bool m_handledGamepadOrRemoteKeyDown;
private bool m_ignoreCancelKeyDowns;
private bool m_isEditModeConfigured;
@@ -44,12 +53,18 @@ partial class ComboBox
// Editable ComboBox is designed to set the focus on TextBox when ComboBox is focused, there are some cases when we don't want
// this behavior eg(Shift+Tab).
private bool m_shouldMoveFocusToTextBox;
- private bool m_isClosingDueToCancel;
+ private bool m_isExpanded;
+ private bool m_isOverlayVisible;
private bool m_restoreIndexSet;
+ private bool m_isClosingDueToCancel;
private bool m_IsPointerOverDropDownOverlay;
private InputDeviceType m_inputDeviceTypeUsedToOpen;
+ private InputDeviceType m_previousInputDeviceTypeUsedToOpen;
+
+ private FrameworkElement m_tpElementPopupChild;
+ private FrameworkElement m_tpElementPopupContent;
private readonly SerialDisposable m_spEditableTextPointerPressedEventHandler = new();
private readonly SerialDisposable m_spEditableTextTappedEventHandler = new();
@@ -65,6 +80,7 @@ partial class ComboBox
private TextBlock m_tpEditableContentPresenterTextBlock;
private ComboBoxItem m_tpSwappedOutComboBoxItem;
+ private Storyboard m_tpClosedStoryboard;
private DependencyObject m_tpGeneratedContainerForContentPresenter;
private int m_iLastGeneratedItemIndexforFaceplate;
private object m_customValueRef;
@@ -78,6 +94,7 @@ partial class ComboBox
private bool IsFullMode => IsSmallFormFactor && m_itemCount > s_itemCountThreshold;
+ private IAsyncInfo m_tpAsyncSelectionInfo;
private int m_itemCount;
private int m_indexToRestoreOnCancel = -1;
diff --git a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.mux.cs b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.mux.cs
index 9af623800c74..f986b26cb032 100644
--- a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.mux.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.mux.cs
@@ -13,6 +13,7 @@
using Uno.UI.Xaml.Input;
using Windows.Foundation;
using Windows.System;
+using static DirectUI.ElevationHelper;
namespace Microsoft.UI.Xaml.Controls;
@@ -279,162 +280,162 @@ private protected override void ChangeVisualState(bool useTransitions)
private void SetContentPresenter(int index, bool forceSelectionBoxToNull = false)
{
- bool bGeneratedComboBoxItem = false;
- DependencyObject spContainer;
- DependencyObject spGeneratedComboBoxItemAsDO;
- ComboBoxItem? spComboBoxItem;
- object? spContent;
- DataTemplate spDataTemplate;
- DataTemplateSelector spDataTemplateSelector;
- GeneratorPosition generatorPosition;
+ UpdateContentPresenter(); // TODO MZ: This should not happen
+ return; // TODO MZ: This should not happen
- Debug.Assert(!IsInline, "ContentPresenter is not used in inline mode.");
+ //bool bGeneratedComboBoxItem = false;
+ //DependencyObject spContainer;
+ //DependencyObject spGeneratedComboBoxItemAsDO;
+ //ComboBoxItem? spComboBoxItem;
+ //object? spContent;
+ //DataTemplate spDataTemplate;
+ //DataTemplateSelector spDataTemplateSelector;
+ //GeneratorPosition generatorPosition;
- UpdateContentPresenter();
- return;
+ //Debug.Assert(!IsInline, "ContentPresenter is not used in inline mode.");
- // Avoid reentrancy.
- if (m_preparingContentPresentersElement)
- {
- return;
- }
+ //// Avoid reentrancy.
+ //if (m_preparingContentPresentersElement)
+ //{
+ // return;
+ //}
- if (m_tpSwappedOutComboBoxItem is not null)
- {
- if (m_tpContentPresenterPart is not null)
- {
- spContent = m_tpContentPresenterPart.Content;
- {
- m_tpContentPresenterPart.Content = null;
- m_tpSwappedOutComboBoxItem.Content = spContent;
- m_tpSwappedOutComboBoxItem = null;
- }
- }
- }
+ //if (m_tpSwappedOutComboBoxItem is not null)
+ //{
+ // if (m_tpContentPresenterPart is not null)
+ // {
+ // spContent = m_tpContentPresenterPart.Content;
+ // {
+ // m_tpContentPresenterPart.Content = null;
+ // m_tpSwappedOutComboBoxItem.Content = spContent;
+ // m_tpSwappedOutComboBoxItem = null;
+ // }
+ // }
+ //}
- ItemContainerGenerator? spGenerator = null; // TODO Uno: Support for ItemContainerGenerator #17808 (Should reference this.ItemContainerGenerator property)
- ItemContainerGenerator? pItemContainerGenerator = spGenerator;
- if (m_iLastGeneratedItemIndexforFaceplate > 0 && pItemContainerGenerator is not null)
- {
- // This container was generated just for the purpose of extracting Content and ContentTemplate.
- // This is the case where we generated an item which was its own container (e.g. defined in XAML or code behind).
- // We keep this until the next item is being put on faceplate or popup is opened so that ItemContainerGenerator.ContainerFromIndex returns the
- // correct container for this item which a developer would expect.
- // We need to remove this item once popup opens (or another item takes its place on faceplate)
- // so that virtualizing panel underneath does not get items out of order.
- // We want to remove instead of recycle because we do not want to change the collection order by reusing containers for different data.
- generatorPosition = pItemContainerGenerator.GeneratorPositionFromIndex(m_iLastGeneratedItemIndexforFaceplate);
- if (generatorPosition.Offset == 0 && generatorPosition.Index >= 0)
- {
- // Only remove if the position returned by Generator is correct
- pItemContainerGenerator.Remove(generatorPosition, 1);
- }
+ //ItemContainerGenerator? spGenerator = null; // TODO Uno: Support for ItemContainerGenerator #17808 (Should reference this.ItemContainerGenerator property)
+ //ItemContainerGenerator? pItemContainerGenerator = spGenerator;
+ //if (m_iLastGeneratedItemIndexforFaceplate > 0 && pItemContainerGenerator is not null)
+ //{
+ // // This container was generated just for the purpose of extracting Content and ContentTemplate.
+ // // This is the case where we generated an item which was its own container (e.g. defined in XAML or code behind).
+ // // We keep this until the next item is being put on faceplate or popup is opened so that ItemContainerGenerator.ContainerFromIndex returns the
+ // // correct container for this item which a developer would expect.
+ // // We need to remove this item once popup opens (or another item takes its place on faceplate)
+ // // so that virtualizing panel underneath does not get items out of order.
+ // // We want to remove instead of recycle because we do not want to change the collection order by reusing containers for different data.
+ // generatorPosition = pItemContainerGenerator.GeneratorPositionFromIndex(m_iLastGeneratedItemIndexforFaceplate);
+ // if (generatorPosition.Offset == 0 && generatorPosition.Index >= 0)
+ // {
+ // // Only remove if the position returned by Generator is correct
+ // pItemContainerGenerator.Remove(generatorPosition, 1);
+ // }
- m_iLastGeneratedItemIndexforFaceplate = -1;
- }
+ // m_iLastGeneratedItemIndexforFaceplate = -1;
+ //}
- if (index == -1)
- {
- if (m_tpContentPresenterPart is not null)
- {
- m_tpContentPresenterPart.ContentTemplateSelector = null;
- m_tpContentPresenterPart.ContentTemplate = null;
- m_tpContentPresenterPart.Content = m_tpEmptyContent;
- }
+ //if (index == -1)
+ //{
+ // if (m_tpContentPresenterPart is not null)
+ // {
+ // m_tpContentPresenterPart.ContentTemplateSelector = null;
+ // m_tpContentPresenterPart.ContentTemplate = null;
+ // m_tpContentPresenterPart.Content = m_tpEmptyContent;
+ // }
- // Only reset the SelectionBoxItem if a custom value is not selected.
- if (forceSelectionBoxToNull || !IsEditable || m_customValueRef is null)
- {
- SelectionBoxItem = null;
- }
+ // // Only reset the SelectionBoxItem if a custom value is not selected.
+ // if (forceSelectionBoxToNull || !IsEditable || m_customValueRef is null)
+ // {
+ // SelectionBoxItem = null;
+ // }
- SelectionBoxItemTemplate = null;
- return;
- }
+ // SelectionBoxItemTemplate = null;
+ // return;
+ //}
- if (m_tpContentPresenterPart is not null)
- {
- m_tpContentPresenterPart.Content = null;
- }
+ //if (m_tpContentPresenterPart is not null)
+ //{
+ // m_tpContentPresenterPart.Content = null;
+ //}
- spContainer = ContainerFromIndex(index);
- spComboBoxItem = spContainer as ComboBoxItem;
+ //spContainer = ContainerFromIndex(index);
+ //spComboBoxItem = spContainer as ComboBoxItem;
- if (spComboBoxItem is null && pItemContainerGenerator is not null)
- {
- bool isNewlyRealized = false;
- generatorPosition = pItemContainerGenerator.GeneratorPositionFromIndex(index);
- pItemContainerGenerator.StartAt(generatorPosition, GeneratorDirection.Forward, true);
- spGeneratedComboBoxItemAsDO = pItemContainerGenerator.GenerateNext(out isNewlyRealized);
- pItemContainerGenerator.Stop();
- m_preparingContentPresentersElement = true;
- m_tpGeneratedContainerForContentPresenter = spGeneratedComboBoxItemAsDO;
- try
- {
- pItemContainerGenerator.PrepareItemContainer(spGeneratedComboBoxItemAsDO);
- }
- finally
- {
- m_tpGeneratedContainerForContentPresenter = null;
- m_preparingContentPresentersElement = false;
- }
- spComboBoxItem = (ComboBoxItem)spGeneratedComboBoxItemAsDO;
- // We dont want to remove the comboBoxItem if it was created explicitly in XAML and exists in Items collection
- // TODO Uno: Missing implementation for ItemContainerGenerator #17808
- //spItem = null; spComboBoxItem.ReadLocalValue(ItemContainerGenerator.ItemForItemContainerProperty);
- //bGeneratedComboBoxItem = IsItemItsOwnContainer(spItem);
- //bGeneratedComboBoxItem = !bGeneratedComboBoxItem;
- m_iLastGeneratedItemIndexforFaceplate = index;
- }
+ //if (spComboBoxItem is null && pItemContainerGenerator is not null)
+ //{
+ // bool isNewlyRealized = false;
+ // generatorPosition = pItemContainerGenerator.GeneratorPositionFromIndex(index);
+ // pItemContainerGenerator.StartAt(generatorPosition, GeneratorDirection.Forward, true);
+ // spGeneratedComboBoxItemAsDO = pItemContainerGenerator.GenerateNext(out isNewlyRealized);
+ // pItemContainerGenerator.Stop();
+ // m_preparingContentPresentersElement = true;
+ // m_tpGeneratedContainerForContentPresenter = spGeneratedComboBoxItemAsDO;
+ // try
+ // {
+ // pItemContainerGenerator.PrepareItemContainer(spGeneratedComboBoxItemAsDO);
+ // }
+ // finally
+ // {
+ // m_tpGeneratedContainerForContentPresenter = null;
+ // m_preparingContentPresentersElement = false;
+ // }
+ // spComboBoxItem = (ComboBoxItem)spGeneratedComboBoxItemAsDO;
+ // // We dont want to remove the comboBoxItem if it was created explicitly in XAML and exists in Items collection
+ // // TODO Uno: Missing implementation for ItemContainerGenerator #17808
+ // //spItem = null; spComboBoxItem.ReadLocalValue(ItemContainerGenerator.ItemForItemContainerProperty);
+ // //bGeneratedComboBoxItem = IsItemItsOwnContainer(spItem);
+ // //bGeneratedComboBoxItem = !bGeneratedComboBoxItem;
+ // m_iLastGeneratedItemIndexforFaceplate = index;
+ //}
- if (spComboBoxItem is null)
- {
- return;
- }
+ //if (spComboBoxItem is null)
+ //{
+ // return;
+ //}
- spContent = spComboBoxItem.Content;
- {
- // Because we can't keep UIElement in 2 different place
- // we need to reset ComboBoxItem.Content property. And we need to do it for UIElement only
- if (spContent is UIElement)
- {
- spComboBoxItem.Content = null;
- if (!bGeneratedComboBoxItem)
- {
- m_tpSwappedOutComboBoxItem = spComboBoxItem;
- }
- }
+ //spContent = spComboBoxItem.Content;
+ //{
+ // // Because we can't keep UIElement in 2 different place
+ // // we need to reset ComboBoxItem.Content property. And we need to do it for UIElement only
+ // if (spContent is UIElement)
+ // {
+ // spComboBoxItem.Content = null;
+ // if (!bGeneratedComboBoxItem)
+ // {
+ // m_tpSwappedOutComboBoxItem = spComboBoxItem;
+ // }
+ // }
- spComboBoxItem.IsPointerOver = false;
- spComboBoxItem.ChangeVisualStateInternal(true);
+ // spComboBoxItem.IsPointerOver = false;
+ // spComboBoxItem.ChangeVisualStateInternal(true);
- // We want the item displayed in the 'selected item' ContentPresenter to have the same visual representation as the
- // items in the Popup's StackPanel, to do that we copy the DataTemplate of the ComboBoxItem.
- spDataTemplate = spComboBoxItem.ContentTemplate;
- spDataTemplateSelector = spComboBoxItem.ContentTemplateSelector;
- if (m_tpContentPresenterPart is not null)
- {
- m_tpContentPresenterPart.Content = spContent;
- m_tpContentPresenterPart.ContentTemplate = spDataTemplate;
- m_tpContentPresenterPart.ContentTemplateSelector = spDataTemplateSelector;
- if (spDataTemplate is null)
- {
- spDataTemplate = m_tpContentPresenterPart.SelectedContentTemplate;
- }
- }
+ // // We want the item displayed in the 'selected item' ContentPresenter to have the same visual representation as the
+ // // items in the Popup's StackPanel, to do that we copy the DataTemplate of the ComboBoxItem.
+ // spDataTemplate = spComboBoxItem.ContentTemplate;
+ // spDataTemplateSelector = spComboBoxItem.ContentTemplateSelector;
+ // if (m_tpContentPresenterPart is not null)
+ // {
+ // m_tpContentPresenterPart.Content = spContent;
+ // m_tpContentPresenterPart.ContentTemplate = spDataTemplate;
+ // m_tpContentPresenterPart.ContentTemplateSelector = spDataTemplateSelector;
+ // if (spDataTemplate is null)
+ // {
+ // spDataTemplate = m_tpContentPresenterPart.SelectedContentTemplate;
+ // }
+ // }
- SelectionBoxItem = spContent;
- SelectionBoxItemTemplate = spDataTemplate;
- }
+ // SelectionBoxItem = spContent;
+ // SelectionBoxItemTemplate = spDataTemplate;
+ //}
- if (bGeneratedComboBoxItem && pItemContainerGenerator is not null)
- {
- // This container was generated just for the purpose of extracting Content and ContentTemplate
- // It is not connected to the visual tree which might have unintended consequences, so remove it
- generatorPosition = pItemContainerGenerator.GeneratorPositionFromIndex(index);
- pItemContainerGenerator.Recycle(generatorPosition, 1);
- m_iLastGeneratedItemIndexforFaceplate = -1;
- }
+ //if (bGeneratedComboBoxItem && pItemContainerGenerator is not null)
+ //{
+ // // This container was generated just for the purpose of extracting Content and ContentTemplate
+ // // It is not connected to the visual tree which might have unintended consequences, so remove it
+ // generatorPosition = pItemContainerGenerator.GeneratorPositionFromIndex(index);
+ // pItemContainerGenerator.Recycle(generatorPosition, 1);
+ // m_iLastGeneratedItemIndexforFaceplate = -1;
+ //}
}
internal void UpdateSelectionBoxItemProperties(int index)
@@ -763,7 +764,7 @@ private void OnOpen()
{
m_tpPopupPart.IsOpen = true;
- bool isDefaultShadowEnabled = IsDefaultShadowEnabled;
+ bool isDefaultShadowEnabled = IsDefaultShadowEnabled(this);
// Cast a shadow
if (isDefaultShadowEnabled)
@@ -827,7 +828,7 @@ private void OnOpen()
// give focus to or select the first item to ensure that keyboarding can function normally.
if (selectedItemIndex >= 0)
{
- SetFocusedItem(selectedItemIndex, m_bShouldCenterSelectedItem /*shouldScrollIntoView*/, true /*forceFocus*/, FocusState.Programmatic);
+ SetFocusedItem(selectedItemIndex, m_bShouldCenterSelectedItem /*shouldScrollIntoView*/, true /*forceFocus*/, FocusState.Programmatic, false);
}
else
{
@@ -2325,5 +2326,17 @@ private void EnsurePresenterReadyForFullMode() { }
private void EnsurePresenterReadyForInlineMode() { }
private void ForceApplyInlineLayoutUpdate() { }
+
+ private void SetIsPopupPannable() { }
+
+ private void SetClosingAnimationDirection() { }
+
+ private void ResetCarouselPanelState() { }
+
+ private void PlayOverlayClosingAnimation() { }
+
+ private void PlayOverlayOpeningAnimation() { }
+
+ private void ClearStateFlagsOnItems() { }
#endif
}