diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3e239730..12bccde0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,13 +37,13 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: - name: Install .NET SDK v${{ env.DOTNET_VERSION }} - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive @@ -74,7 +74,7 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: - name: Configure Pagefile - uses: al-cheb/configure-pagefile-action@v1.3 + uses: al-cheb/configure-pagefile-action@v1.4 with: minimum-size: 32GB maximum-size: 32GB @@ -90,7 +90,7 @@ jobs: Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps' -Name 'DumpType' -Type DWord -Value '2' - name: Install .NET SDK v${{ env.DOTNET_VERSION }} - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} @@ -100,7 +100,7 @@ jobs: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive @@ -178,7 +178,7 @@ jobs: # Run tests - name: Setup VSTest Path - uses: darenm/Setup-VSTest@v1.2 + uses: darenm/setup-vstest@3a16d909a1f3bbc65b52f8270d475d905e7d3e44 - name: Install Testspace Module uses: testspace-com/setup-testspace@v1 @@ -199,14 +199,14 @@ jobs: if: ${{ always() && (steps.test-generator.conclusion == 'success' || steps.test-platform.conclusion == 'success') }} - name: Artifact - Diagnostic Logs - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ (env.ENABLE_DIAGNOSTICS == 'true' || env.COREHOST_TRACE != '') && always() }} with: - name: build-logs + name: build-logs-${{ matrix.platform }} path: ./**/*.*log - name: Artifact - ILC Repro - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ (env.ENABLE_DIAGNOSTICS == 'true' || env.COREHOST_TRACE != '') && always() }} with: name: ilc-repro @@ -221,7 +221,7 @@ jobs: echo "DUMP_FILE=$(Get-ChildItem .\CrashDumps\*.dmp -ErrorAction SilentlyContinue)" >> $env:GITHUB_OUTPUT - name: Artifact - WER crash dumps - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ (env.ENABLE_DIAGNOSTICS == 'true' || env.COREHOST_TRACE != '') && always() }} with: name: CrashDumps-${{ matrix.platform }} @@ -234,17 +234,17 @@ jobs: dotnet-dump analyze ${{ steps.detect-dump.outputs.DUMP_FILE }} -c "clrstack" -c "pe -lines" -c "exit" - name: Upload Package List - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ env.IS_PR == 'false' }} with: - name: nuget-list + name: nuget-list-${{ matrix.platform }} if-no-files-found: error path: | ${{ github.workspace }}/.github/workflows/SignClientFileList.txt # if we're not doing a PR build (or it's a PR from a fork) then we upload our packages so we can sign as a separate job or have available to test. - name: Upload Packages as Artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ env.IS_PR == 'false' || github.event.pull_request.head.repo.full_name != github.repository }} with: name: nuget-packages-${{ matrix.platform }} @@ -266,18 +266,18 @@ jobs: steps: - name: Install .NET SDK v${{ env.DOTNET_VERSION }} - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} - name: Download Package List - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: nuget-list + name: nuget-list-${{ matrix.platform }} path: ./ - name: Download built packages for ${{ matrix.platform }} - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: nuget-packages-${{ matrix.platform }} path: ./packages @@ -310,7 +310,7 @@ jobs: dotnet nuget push "**/*.nupkg" --api-key dummy --source MainLatest --skip-duplicate - name: Upload Signed Packages as Artifacts (for release) - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ env.IS_RELEASE == 'true' }} with: name: signed-nuget-packages-${{ matrix.platform }} @@ -331,12 +331,12 @@ jobs: steps: - name: Install .NET SDK v${{ env.DOTNET_VERSION }} - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} - name: Download signed packages for ${{ matrix.platform }} - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: signed-nuget-packages-${{ matrix.platform }} path: ./packages @@ -354,7 +354,7 @@ jobs: steps: - name: Install .NET SDK v${{ env.DOTNET_VERSION }} - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} @@ -364,7 +364,7 @@ jobs: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive @@ -394,7 +394,7 @@ jobs: # TODO: Do we want to run tests here? Can we do that on linux easily? - name: Artifact - Diagnostic Logs - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ (env.ENABLE_DIAGNOSTICS == 'true' || env.COREHOST_TRACE != '') && always() }} with: name: linux-logs diff --git a/components/Animations/src/Extensions/CompositorExtensions.cs b/components/Animations/src/Extensions/CompositorExtensions.cs index 5358ab80..b9944195 100644 --- a/components/Animations/src/Extensions/CompositorExtensions.cs +++ b/components/Animations/src/Extensions/CompositorExtensions.cs @@ -109,7 +109,9 @@ public static BooleanKeyFrameAnimation CreateBooleanKeyFrameAnimation( animation.InsertKeyFrame(0, from.Value); } - animation.Target = target; + if (target is not null) + animation.Target = target; + animation.Direction = direction; animation.IterationBehavior = iterationBehavior; animation.IterationCount = iterationCount; @@ -170,7 +172,9 @@ public static ScalarKeyFrameAnimation CreateScalarKeyFrameAnimation( animation.InsertKeyFrame(0, from.Value); } - animation.Target = target; + if (target is not null) + animation.Target = target; + animation.Direction = direction; animation.IterationBehavior = iterationBehavior; animation.IterationCount = iterationCount; @@ -231,7 +235,9 @@ public static Vector2KeyFrameAnimation CreateVector2KeyFrameAnimation( animation.InsertKeyFrame(0, from.Value); } - animation.Target = target; + if (target is not null) + animation.Target = target; + animation.Direction = direction; animation.IterationBehavior = iterationBehavior; animation.IterationCount = iterationCount; @@ -292,7 +298,9 @@ public static Vector3KeyFrameAnimation CreateVector3KeyFrameAnimation( animation.InsertKeyFrame(0, from.Value); } - animation.Target = target; + if (target is not null) + animation.Target = target; + animation.Direction = direction; animation.IterationBehavior = iterationBehavior; animation.IterationCount = iterationCount; @@ -353,7 +361,9 @@ public static Vector4KeyFrameAnimation CreateVector4KeyFrameAnimation( animation.InsertKeyFrame(0, from.Value); } - animation.Target = target; + if (target is not null) + animation.Target = target; + animation.Direction = direction; animation.IterationBehavior = iterationBehavior; animation.IterationCount = iterationCount; @@ -414,7 +424,9 @@ public static ColorKeyFrameAnimation CreateColorKeyFrameAnimation( animation.InsertKeyFrame(0, from.Value); } - animation.Target = target; + if (target is not null) + animation.Target = target; + animation.Direction = direction; animation.IterationBehavior = iterationBehavior; animation.IterationCount = iterationCount; @@ -475,7 +487,9 @@ public static QuaternionKeyFrameAnimation CreateQuaternionKeyFrameAnimation( animation.InsertKeyFrame(0, from.Value); } - animation.Target = target; + if (target is not null) + animation.Target = target; + animation.Direction = direction; animation.IterationBehavior = iterationBehavior; animation.IterationCount = iterationCount; diff --git a/components/Behaviors/samples/Behaviors.Animations.md b/components/Behaviors/samples/AnimationSet.md similarity index 97% rename from components/Behaviors/samples/Behaviors.Animations.md rename to components/Behaviors/samples/AnimationSet.md index 6b91520e..4dc8406a 100644 --- a/components/Behaviors/samples/Behaviors.Animations.md +++ b/components/Behaviors/samples/AnimationSet.md @@ -119,10 +119,6 @@ Here is an example that showcases both the sequential mode for animations as wel The same functionality with respect to cancellation applies to `AnimationSet` as well: each individual invocation on an UI element internally gets its own cancellation token, which can be used to stop a running animation by invoking the `Stop()` method or one of its overloads. The same token is also forwarded to all invoked activities in the schedule, so stopping an animation set will also automatically stop all linked animations and activities as well. -Here's an example of how all these various explicit animations can be combined together (including some of the new effect animations too): - -![AnimationSet in sequential mode and with combined animations](../resources/images/AnimationSet.gif) - ## Behaviors If you are also referencing the `Behaviors` package, it will be possible to also use behaviors and actions to better support the new APIs, such as by automatically triggering an animation when a given event is raised, entirely from XAML. There are four main types being introduced in this package that interoperate with the Animation APIs: @@ -203,7 +199,3 @@ Here is an example of how the new `PipelineVisualFactory` type can be combined w ``` Here we are setting the `IsAnimatable` property for the effects we want to animate after creating the brush. This is necessary because Win2D/Composition effects do not support animation by default, and additional setup is required when creating a Composition brush to enable this functionality. Effects in a pipeline are not just all configured as being animatable by default both in order to reduce the overhead, and because there is a limit on the number of effects that can be animated in a single brush. Making this more advanced functionality opt-in for users ensures that it will still be possible to animate effects even within very large pipelines, without incurring into issues due to this limit. - -And here is the final result from the code above, with an image and some text as content: - -![AnimationSet used to animate effects in a custom pipeline](../resources/images/EffectAnimations.gif) diff --git a/components/Collections/samples/IncrementalLoadingCollectionSample.xaml.cs b/components/Collections/samples/IncrementalLoadingCollectionSample.xaml.cs index 8812f26c..4b02acd3 100644 --- a/components/Collections/samples/IncrementalLoadingCollectionSample.xaml.cs +++ b/components/Collections/samples/IncrementalLoadingCollectionSample.xaml.cs @@ -17,7 +17,7 @@ public IncrementalLoadingCollectionSample() private void Load() { // IncrementalLoadingCollection can be bound to a GridView or a ListView. In this case it is a ListView called PeopleListView. - var collection = new IncrementalLoadingCollection(); + var collection = new IncrementalLoadingCollection(new PeopleSource()); PeopleListView.ItemsSource = collection; // Binds the collection to the page DataContext in order to use its IsLoading and HasMoreItems properties. diff --git a/components/Collections/src/AdvancedCollectionView/AdvancedCollectionView.cs b/components/Collections/src/AdvancedCollectionView/AdvancedCollectionView.cs index 42f7ee85..416d87f8 100644 --- a/components/Collections/src/AdvancedCollectionView/AdvancedCollectionView.cs +++ b/components/Collections/src/AdvancedCollectionView/AdvancedCollectionView.cs @@ -13,6 +13,9 @@ namespace CommunityToolkit.WinUI.Collections; /// /// A collection view implementation that supports filtering, sorting and incremental loading /// +#if NET8_0_OR_GREATER +[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Item sorting uses reflection to get property types and may not be AOT compatible.")] +#endif public partial class AdvancedCollectionView : IAdvancedCollectionView, INotifyPropertyChanged, ISupportIncrementalLoading, IComparer { private readonly List _view; diff --git a/components/Collections/src/IncrementalLoadingCollection/IncrementalLoadingCollection.cs b/components/Collections/src/IncrementalLoadingCollection/IncrementalLoadingCollection.cs index 41cd4ab1..12a0a731 100644 --- a/components/Collections/src/IncrementalLoadingCollection/IncrementalLoadingCollection.cs +++ b/components/Collections/src/IncrementalLoadingCollection/IncrementalLoadingCollection.cs @@ -130,6 +130,11 @@ private set /// An that is called if an error occurs during data retrieval. /// /// +#if NET8_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("This constructor is not AOT compatible and will be removed in a future version.")] +#endif + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("This constructor is not AOT compatible and will be removed in a future version. Use the other constructor and provide a source collection to use.")] public IncrementalLoadingCollection(int itemsPerPage = 20, Action Action Action : this(Activator.CreateInstance(), itemsPerPage, onStartLoading, onEndLoading, onError) { diff --git a/components/Converters/samples/Converters.md b/components/Converters/samples/Converters.md index c908a1e8..62fe164a 100644 --- a/components/Converters/samples/Converters.md +++ b/components/Converters/samples/Converters.md @@ -76,7 +76,7 @@ Converts a source string from the App resources and returns its value, if found. ## StringFormatConverter -This allows you to format a string property upon binding wrapping [string.Format](https://learn.microsoft.com/dotnet/api/system.string.format?view=netstandard-2.0). +This allows you to format a string property upon binding wrapping [string.Format](https://learn.microsoft.com/dotnet/api/system.string.format?view=netstandard-2.0&preserve-view=true). It only allows for a single input value (the binding string), but can be formatted with the regular string.Format methods. diff --git a/components/Converters/src/TaskResultConverter.cs b/components/Converters/src/TaskResultConverter.cs index 1c7cc61d..72bc54a7 100644 --- a/components/Converters/src/TaskResultConverter.cs +++ b/components/Converters/src/TaskResultConverter.cs @@ -14,6 +14,9 @@ namespace CommunityToolkit.WinUI.Converters; /// The methods in this converter will safely return if the input /// task is not set yet, still running, has faulted, or has been canceled. /// +#if NET8_0_OR_GREATER +[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("This method uses reflection to try to access the Task.Result property of the input Task instance.")] +#endif public sealed class TaskResultConverter : IValueConverter { /// diff --git a/components/Extensions/samples/DispatcherQueueExtensions.md b/components/Extensions/samples/DispatcherQueueExtensions.md index e77ed350..73fb9438 100644 --- a/components/Extensions/samples/DispatcherQueueExtensions.md +++ b/components/Extensions/samples/DispatcherQueueExtensions.md @@ -49,7 +49,7 @@ int someOtherValue = await dispatcherQueue.EnqueueAsync(async () => }); ``` -## Migrating from [`DispatcherHelper`](..\helpers\DispatcherHelper.md) +## Migrating from DispatcherHelper The [`CoreDispatcher`](https://learn.microsoft.com/uwp/api/windows.ui.core.coredispatcher) is being deprecated (and it will no longer work with XAML Islands or WinUI 3) and should no longer be used, as it had a number of limitations. Specifically, it relied on the assumption that each window had its own UI thread tied to it, which is not always the case. The new `DispatcherQueue` instead can be used going forwards, and it requires some changes in code that was previously relying on `CoreDispatcher` and `DispatcherHelper`. Specifically, a background thread can no longer retrieve the `CoreDispatcher` by just accessing the dispatcher associated to the "main window" for the application, because this concept does not apply anymore. Instead, a `DispatcherQueue` instance needs to be retrieved on the UI thread and cached for later use in a background thread. diff --git a/components/Extensions/samples/FrameworkElementExtensions.md b/components/Extensions/samples/FrameworkElementExtensions.md index 1839618d..be5167f1 100644 --- a/components/Extensions/samples/FrameworkElementExtensions.md +++ b/components/Extensions/samples/FrameworkElementExtensions.md @@ -99,7 +99,7 @@ Here is how you can easily set a custom cursor type for a target `FrameworkEleme ``` > [!NOTE] -> Even though Microsoft recommends in [UWP Design guidelines](https://learn.microsoft.com/uwp/input-and-devices/mouse-interactions#cursors) hover effects instead of custom cursors over interactive elements, custom cursors can be useful in some specific scenarios. +> Even though Microsoft recommends in [UWP Design guidelines](https://learn.microsoft.com/windows/apps/design/input/mouse-interactions#cursors) hover effects instead of custom cursors over interactive elements, custom cursors can be useful in some specific scenarios. > [!WARNING] > Because the UWP framework does not support metadata on attached properties, specifically the [`FrameworkPropertyMetadata.Inherits`](https://learn.microsoft.com/dotnet/api/system.windows.frameworkpropertymetadata.-ctor#System_Windows_FrameworkPropertyMetadata__ctor_System_Object_System_Windows_FrameworkPropertyMetadataOptions_System_Windows_PropertyChangedCallback_System_Windows_CoerceValueCallback_) flag, the `Cursor` property might not work properly in some very specific XAML layout scenarios when combining nested `FrameworkElement`-s with different `CoreCursorType` values set on them. diff --git a/components/Extensions/samples/ShadowAnimations.md b/components/Extensions/samples/ShadowAnimations.md index 41db67cb..3c44de3a 100644 --- a/components/Extensions/samples/ShadowAnimations.md +++ b/components/Extensions/samples/ShadowAnimations.md @@ -12,7 +12,7 @@ issue-id: 0 icon: Assets/ShadowAnimation.png --- -Either type of Attached Shadow can be easily animated using the Toolkit's [`AnimationSet`](../animations/AnimationSet.md) api. These provide an easy XAML based way to animate a wide variety of elements, including a variety of shadow properties. They can also be animated with any other composition animation technique in code-behind as well using either the [`AnimationBuilder`](../animations/AnimationBuilder.md) or built-in composition animations. +Either type of Attached Shadow can be easily animated using the Toolkit's [`AnimationSet`](../animations/AnimationSet.md) api. These provide an easy XAML based way to animate a wide variety of elements, including a variety of shadow properties. They can also be animated with any other composition animation technique in code-behind as well using either the [`AnimationBuilder`](../Behaviors/AnimationSet.md) or built-in composition animations. > **Platform APIs:** `BlurRadiusDropShadowAnimation`, `ColorDropShadowAnimation`, `OffsetDropShadowAnimation`, `OpacityDropShadowAnimation` diff --git a/components/Extensions/src/Element/FrameworkElementExtensions.Mouse.cs b/components/Extensions/src/Element/FrameworkElementExtensions.Mouse.cs index d1bced06..a1d74a59 100644 --- a/components/Extensions/src/Element/FrameworkElementExtensions.Mouse.cs +++ b/components/Extensions/src/Element/FrameworkElementExtensions.Mouse.cs @@ -101,6 +101,7 @@ private static void Element_PointerEntered(object sender, PointerRoutedEventArgs CursorShape cursor = GetCursor((FrameworkElement)sender); #if !WINAPPSDK + if (Window.Current?.CoreWindow is not null) Window.Current.CoreWindow.PointerCursor = _cursors[cursor]; #endif } @@ -124,6 +125,7 @@ private static void Element_PointerExited(object sender, PointerRoutedEventArgs } #if !WINAPPSDK + if (Window.Current?.CoreWindow is not null) Window.Current.CoreWindow.PointerCursor = cursor; #endif } @@ -138,6 +140,7 @@ private static void ElementOnUnloaded(object sender, RoutedEventArgs routedEvent // when the element is programatically unloaded, reset the cursor back to default // this is necessary when click triggers immediate change in layout and PointerExited is not called #if !WINAPPSDK + if (Window.Current?.CoreWindow is not null) Window.Current.CoreWindow.PointerCursor = _defaultCursor; #endif } diff --git a/components/Extensions/src/Markup/EnumValuesExtension.cs b/components/Extensions/src/Markup/EnumValuesExtension.cs index a18cba92..d0a1751e 100644 --- a/components/Extensions/src/Markup/EnumValuesExtension.cs +++ b/components/Extensions/src/Markup/EnumValuesExtension.cs @@ -8,6 +8,9 @@ namespace CommunityToolkit.WinUI; /// A markup extension that returns a collection of values of a specific /// [MarkupExtensionReturnType(ReturnType = typeof(Array))] +#if NET8_0_OR_GREATER +[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("It might not be possible to create an array of a user-defined enum type at runtime.")] +#endif public sealed class EnumValuesExtension : MarkupExtension { /// diff --git a/components/Helpers/samples/ColorHelper.md b/components/Helpers/samples/ColorHelper.md index 52207fab..e66593b0 100644 --- a/components/Helpers/samples/ColorHelper.md +++ b/components/Helpers/samples/ColorHelper.md @@ -1,6 +1,6 @@ --- title: ColorHelper -author: +author: niels9001 description: Convert colors from text names, HTML hex, HSV, or HSL to Windows UI Colors (and back again). keywords: Helpers, Theming, theme listener, themes, screenunithelper, colorhelper dev_langs: diff --git a/components/Helpers/samples/DesignTimeHelper.md b/components/Helpers/samples/DesignTimeHelper.md index c592c41e..c160d1db 100644 --- a/components/Helpers/samples/DesignTimeHelper.md +++ b/components/Helpers/samples/DesignTimeHelper.md @@ -1,6 +1,6 @@ --- title: DesignTimeHelpers -author: +author: niels9001 description: Class used to provide helpers for design time. keywords: Helpers, designtimehelpers, dev_langs: diff --git a/components/Helpers/samples/ScreenUnitHelper.md b/components/Helpers/samples/ScreenUnitHelper.md index 1089c839..d875a24e 100644 --- a/components/Helpers/samples/ScreenUnitHelper.md +++ b/components/Helpers/samples/ScreenUnitHelper.md @@ -1,6 +1,6 @@ --- title: ScreenUnitHelper -author: +author: niels9001 description: Convert screen units to another screen unit. keywords: Helpers, screenunithelper, dev_langs: diff --git a/components/Helpers/src/ThemeListener.cs b/components/Helpers/src/ThemeListener.cs index 29b2c289..af35e3d9 100644 --- a/components/Helpers/src/ThemeListener.cs +++ b/components/Helpers/src/ThemeListener.cs @@ -76,7 +76,7 @@ public ThemeListener(DispatcherQueue? dispatcherQueue = null) DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread(); - if (Window.Current != null) + if (Window.Current?.CoreWindow is not null) { _accessible.HighContrastChanged += Accessible_HighContrastChanged; _settings.ColorValuesChanged += Settings_ColorValuesChanged; @@ -163,7 +163,7 @@ public void Dispose() { _accessible.HighContrastChanged -= Accessible_HighContrastChanged; _settings.ColorValuesChanged -= Settings_ColorValuesChanged; - if (Window.Current != null) + if (Window.Current?.CoreWindow is not null) { Window.Current.CoreWindow.Activated -= CoreWindow_Activated; } diff --git a/components/Primitives/samples/DockPanel.md b/components/Primitives/samples/DockPanel.md index bc6504f9..3c342678 100644 --- a/components/Primitives/samples/DockPanel.md +++ b/components/Primitives/samples/DockPanel.md @@ -21,12 +21,14 @@ You can set DockPanel LastChildFill property to true if you want the last item a ```xaml + xmlns:controls="using:CommunityToolkit.WinUI.Controls"> - - - - - - + + + + + + + + ``` diff --git a/components/Primitives/src/DockPanel/DockPanel.cs b/components/Primitives/src/DockPanel/DockPanel.cs index 542b95c7..759e2262 100644 --- a/components/Primitives/src/DockPanel/DockPanel.cs +++ b/components/Primitives/src/DockPanel/DockPanel.cs @@ -96,64 +96,83 @@ protected override Size MeasureOverride(Size availableSize) var parentHeight = 0.0; var accumulatedWidth = Padding.Left + Padding.Right; var accumulatedHeight = Padding.Top + Padding.Bottom; - + var leftSpacing = false; var topSpacing = false; var rightSpacing = false; var bottomSpacing = false; - - foreach (var child in Children) + var childrenCount = LastChildFill ? Children.Count - 1 : Children.Count; + + for (var index = 0; index < childrenCount; ++index) { + var child = Children[index]; var childConstraint = new Size( GetPositiveOrZero(availableSize.Width - accumulatedWidth), GetPositiveOrZero(availableSize.Height - accumulatedHeight)); - + child.Measure(childConstraint); var childDesiredSize = child.DesiredSize; - + switch ((Dock)child.GetValue(DockProperty)) { case Dock.Left: + leftSpacing = true; + parentHeight = Math.Max(parentHeight, accumulatedHeight + childDesiredSize.Height); if (childConstraint.Width is not 0) accumulatedWidth += HorizontalSpacing; - leftSpacing = true; - parentHeight = Math.Max(parentHeight, accumulatedHeight + childDesiredSize.Height - VerticalSpacing); accumulatedWidth += childDesiredSize.Width; break; - + case Dock.Right: + rightSpacing = true; + parentHeight = Math.Max(parentHeight, accumulatedHeight + childDesiredSize.Height); if (childConstraint.Width is not 0) accumulatedWidth += HorizontalSpacing; - rightSpacing = true; - parentHeight = Math.Max(parentHeight, accumulatedHeight + childDesiredSize.Height - VerticalSpacing); accumulatedWidth += childDesiredSize.Width; break; - + case Dock.Top: + topSpacing = true; + parentWidth = Math.Max(parentWidth, accumulatedWidth + childDesiredSize.Width); if (childConstraint.Height is not 0) accumulatedHeight += VerticalSpacing; - topSpacing = true; - parentWidth = Math.Max(parentWidth, accumulatedWidth + childDesiredSize.Width - HorizontalSpacing); accumulatedHeight += childDesiredSize.Height; break; - + case Dock.Bottom: + bottomSpacing = true; + parentWidth = Math.Max(parentWidth, accumulatedWidth + childDesiredSize.Width); if (childConstraint.Height is not 0) accumulatedHeight += VerticalSpacing; - bottomSpacing = true; - parentWidth = Math.Max(parentWidth, accumulatedWidth + childDesiredSize.Width - HorizontalSpacing); accumulatedHeight += childDesiredSize.Height; break; } } - - if (leftSpacing || rightSpacing) - accumulatedWidth -= HorizontalSpacing; - if (bottomSpacing || topSpacing) - accumulatedHeight -= VerticalSpacing; - - parentWidth = Math.Max(parentWidth, accumulatedWidth); - parentHeight = Math.Max(parentHeight, accumulatedHeight); + + if (LastChildFill) + { + var child = Children[Children.Count - 1]; + var childConstraint = new Size( + GetPositiveOrZero(availableSize.Width - accumulatedWidth), + GetPositiveOrZero(availableSize.Height - accumulatedHeight)); + + child.Measure(childConstraint); + var childDesiredSize = child.DesiredSize; + parentHeight = Math.Max(parentHeight, accumulatedHeight + childDesiredSize.Height); + parentWidth = Math.Max(parentWidth, accumulatedWidth + childDesiredSize.Width); + accumulatedHeight += childDesiredSize.Height; + accumulatedWidth += childDesiredSize.Width; + } + else + { + if (leftSpacing || rightSpacing) + accumulatedWidth -= HorizontalSpacing; + if (bottomSpacing || topSpacing) + accumulatedHeight -= VerticalSpacing; + } + + parentWidth = Math.Min(availableSize.Width, Math.Max(parentWidth, accumulatedWidth)); + parentHeight = Math.Min(availableSize.Height, Math.Max(parentHeight, accumulatedHeight)); return new Size(parentWidth, parentHeight); } diff --git a/components/RangeSelector/src/RangeSelector.xaml b/components/RangeSelector/src/RangeSelector.xaml index ea451405..934c62a3 100644 --- a/components/RangeSelector/src/RangeSelector.xaml +++ b/components/RangeSelector/src/RangeSelector.xaml @@ -1,7 +1,11 @@  + xmlns:controls="using:CommunityToolkit.WinUI.Controls" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:not_win="http://uno.ui/not_win" + xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + mc:Ignorable="not_win">