Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
<Label Text="ThumbColor=Orange" Style="{StaticResource Headline}"/>
<Slider ThumbColor="Orange"/>

<Label Text="ThumbImageSource=coffee.png" Style="{StaticResource Headline}"/>
<Slider x:Name="ImageSlider" ThumbImageSource="coffee.png" />
<Label Text="ThumbImageSource=thumb_image.png" Style="{StaticResource Headline}"/>
<Slider x:Name="ImageSlider" ThumbImageSource="thumb_image.png" />
<Button Text="Toggle Image" Clicked="ToggleImageSource" />

<Label Text="Custom Slider (Red MinimumTrackColor, Green MaximumTrackColor, Blue ThumbColor)" Style="{StaticResource Headline}"/>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 13 additions & 2 deletions src/Core/src/Handlers/Slider/SliderHandler.Windows.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#nullable enable
using Microsoft.Maui.Graphics;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
Expand All @@ -8,6 +9,7 @@ namespace Microsoft.Maui.Handlers
{
public partial class SliderHandler : ViewHandler<ISlider, Slider>
{
Size? _thumbSize;
PointerEventHandler? _pointerPressedHandler;
PointerEventHandler? _pointerReleasedHandler;

Expand Down Expand Up @@ -45,6 +47,8 @@ protected override void DisconnectHandler(Slider platformView)

_pointerPressedHandler = null;
_pointerReleasedHandler = null;

_thumbSize = null;
}

public static void MapMinimum(ISliderHandler handler, ISlider slider)
Expand Down Expand Up @@ -83,16 +87,23 @@ public static void MapThumbImageSource(ISliderHandler handler, ISlider slider)

if (handler?.PlatformView is MauiSlider mauiSlider)
{
mauiSlider.UpdateThumbImageSourceAsync(slider, provider).FireAndForget(handler);
mauiSlider.UpdateThumbImageSourceAsync(slider, provider, (handler as SliderHandler)?._thumbSize).FireAndForget(handler);
}
}

void OnPlatformViewLoaded(object sender, RoutedEventArgs e)
{
var platformView = sender as Slider;

if (platformView != null)
if (platformView is not null)
{
var thumb = platformView.GetFirstDescendant<Thumb>();

if (thumb is not null)
_thumbSize = new Size(thumb.Width, thumb.Height);

platformView.ValueChanged += OnPlatformValueChanged;
}
}

void OnPlatformValueChanged(object? sender, RangeBaseValueChangedEventArgs e)
Expand Down
39 changes: 37 additions & 2 deletions src/Core/src/Platform/Windows/SliderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
#nullable enable
using System;
using System.Threading.Tasks;
using Microsoft.Maui.Graphics;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Media.Imaging;

namespace Microsoft.Maui.Platform
{
Expand Down Expand Up @@ -99,21 +103,52 @@ public static void UpdateThumbColor(this Slider platformSlider, ISlider slider)
"SliderThumbBackgroundDisabled",
};

internal static async Task UpdateThumbImageSourceAsync(this MauiSlider nativeSlider, ISlider slider, IImageSourceServiceProvider? provider)
internal static async Task UpdateThumbImageSourceAsync(this MauiSlider nativeSlider, ISlider slider, IImageSourceServiceProvider? provider, Size? defaultThumbSize)
{
var thumbImageSource = slider.ThumbImageSource;

if (thumbImageSource == null)
{
nativeSlider.ThumbImageSource = null;

var thumb = nativeSlider.GetFirstDescendant<Thumb>();

if (defaultThumbSize.HasValue && thumb is not null)
{
thumb.Height = defaultThumbSize.Value.Height;
thumb.Width = defaultThumbSize.Value.Width;
}

return;
}

if (provider != null && thumbImageSource != null)
{
var service = provider.GetRequiredImageSourceService(thumbImageSource);
var nativeThumbImageSource = await service.GetImageSourceAsync(thumbImageSource);

var nativeThumbImage = nativeThumbImageSource?.Value;

// BitmapImage is a special case that has an event when the image is loaded
// when this happens, we want to resize the thumb
if (nativeThumbImage is BitmapImage bitmapImage)
{
bitmapImage.ImageOpened += OnImageOpened;

void OnImageOpened(object sender, RoutedEventArgs e)
{
bitmapImage.ImageOpened -= OnImageOpened;

if (nativeSlider.TryGetFirstDescendant<Thumb>(out var thumb))
{
thumb.Height = bitmapImage.PixelHeight;
thumb.Width = bitmapImage.PixelWidth;
}

if (nativeSlider.Parent is FrameworkElement frameworkElement)
frameworkElement.InvalidateMeasure();
};
}

nativeSlider.ThumbImageSource = nativeThumbImageSource?.Value;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Threading.Tasks;
using Microsoft.Maui.DeviceTests.Stubs;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Xunit;

namespace Microsoft.Maui.DeviceTests
Expand Down Expand Up @@ -35,6 +36,69 @@ public async Task SmallChangeInitializesCorrectly(double min, double max, double
Assert.True(expected != 0);
}

[Fact]
public async Task ThumbImageSourceUpdatesCorrectly()
{
var slider = new SliderStub
{
Maximum = 10,
Minimum = 0,
Value = 5,
ThumbImageSource = new FileImageSourceStub("black.png"),
};

// Update the Slider ThumbImageSource
slider.ThumbImageSource = new FileImageSourceStub("red.png");

await InvokeOnMainThreadAsync(async () =>
{
var handler = CreateHandler(slider);

bool imageLoaded = await Wait(() => ImageSourceLoaded(handler));

Assert.True(imageLoaded);

await Task.Delay(100);

var expectedColor = Color.FromArgb("#FF0000");
await handler.PlatformView.AssertContainsColor(expectedColor);
});
}

[Theory]
[InlineData("red.png", 100, 100)]
[InlineData("black.png", 100, 100)]
public async Task ThumbImageSourceSizeIsCorrect(string filename, double thumbHeight, double thumbWidth)
{
var slider = new SliderStub
{
Maximum = 10,
Minimum = 0,
Value = 5,
ThumbImageSource = new FileImageSourceStub("black.png"),
};

await InvokeOnMainThreadAsync(async () =>
{
var handler = CreateHandler(slider);

bool imageLoaded = await Wait(() => ImageSourceLoaded(handler));
Assert.True(imageLoaded);

await handler.PlatformView.AttachAndRun(async () =>
{
// Update the Slider ThumbImageSource
slider.ThumbImageSource = new FileImageSourceStub(filename);

await Task.Delay(100);

var nativeThumbSize = GetNativeThumbSize(handler);
Assert.Equal(nativeThumbSize.Height, thumbHeight);
Assert.Equal(nativeThumbSize.Width, thumbWidth);
});
});
}

Slider GetNativeSlider(SliderHandler sliderHandler) =>
sliderHandler.PlatformView;

Expand All @@ -48,6 +112,23 @@ double GetNativeMaximum(SliderHandler sliderHandler) =>
GetNativeSlider(sliderHandler).Maximum;

double GetSmallChange(SliderHandler sliderHandler) =>
GetNativeSlider(sliderHandler).SmallChange;
GetNativeSlider(sliderHandler).SmallChange;

Size GetNativeThumbSize(SliderHandler sliderHandler)
{
var nativeSlider = GetNativeSlider(sliderHandler);

if(nativeSlider.GetFirstDescendant<Thumb>() is Thumb thumb)
{
return new Size(thumb.Width, thumb.Height);
}

return Size.Zero;
}

bool ImageSourceLoaded(SliderHandler sliderHandler)
{
return (sliderHandler.PlatformView as MauiSlider)?.ThumbImageSource != null;
}
}
}