### Description of Change

Merge main into net9.0
This commit is contained in:
Shane Neuville 2024-08-22 19:01:11 -05:00 коммит произвёл GitHub
Родитель 4626f423be ea2a01a523
Коммит 23ccf19441
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
40 изменённых файлов: 1270 добавлений и 67 удалений

Просмотреть файл

@ -209,6 +209,26 @@ Task("dotnet-samples")
RunMSBuildWithDotNet(projectsToBuild, properties, binlogPrefix: "sample-"); RunMSBuildWithDotNet(projectsToBuild, properties, binlogPrefix: "sample-");
}); });
// Builds the host app for the UI Tests
Task("uitests-apphost")
.IsDependentOn("dotnet-buildtasks")
.Does(() =>
{
var tempDir = PrepareSeparateBuildContext("samplesTest");
var properties = new Dictionary<string, string>();
if(useNuget)
{
properties = new Dictionary<string, string> {
["UseWorkload"] = "true",
// ["GenerateAppxPackageOnBuild"] = "true",
["RestoreConfigFile"] = tempDir.CombineWithFilePath("NuGet.config").FullPath,
};
}
RunMSBuildWithDotNet("./src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj", properties, binlogPrefix: "uitests-apphost-");
});
Task("dotnet-legacy-controlgallery") Task("dotnet-legacy-controlgallery")
.IsDependentOn("dotnet-legacy-controlgallery-android") .IsDependentOn("dotnet-legacy-controlgallery-android")
.IsDependentOn("dotnet-legacy-controlgallery-ios"); .IsDependentOn("dotnet-legacy-controlgallery-ios");

Просмотреть файл

@ -49,7 +49,7 @@ steps:
- pwsh: echo "##vso[task.prependpath]$(DotNet.Dir)" - pwsh: echo "##vso[task.prependpath]$(DotNet.Dir)"
displayName: 'Add .NET to PATH' displayName: 'Add .NET to PATH'
- pwsh: ./build.ps1 --target=dotnet-samples --configuration="${{ parameters.configuration }}" --${{ parameters.platform }} --verbosity=diagnostic --usenuget=false --runtimevariant="${{ parameters.runtimeVariant }}" - pwsh: ./build.ps1 --target=uitests-apphost --configuration="${{ parameters.configuration }}" --${{ parameters.platform }} --verbosity=diagnostic --usenuget=false --runtimevariant="${{ parameters.runtimeVariant }}"
displayName: 'Build the samples' displayName: 'Build the samples'
- bash: | - bash: |

Просмотреть файл

@ -998,23 +998,35 @@ namespace Microsoft.Maui.Controls.Build.Tasks
// IL_008e: newobj instance void class [mscorlib]System.Tuple`2<class [mscorlib]System.Func`2<class ViewModel, object>, string>::'.ctor'(!0, !1) // IL_008e: newobj instance void class [mscorlib]System.Tuple`2<class [mscorlib]System.Func`2<class ViewModel, object>, string>::'.ctor'(!0, !1)
// IL_0093: stelem.ref // IL_0093: stelem.ref
yield return Create(Ldc_I4, properties.Count); var handlers = new List<(MethodDefinition PartGetter, string PropertyName)>();
yield return Create(Newarr, tupleRef); for (int i = 0; i < properties.Count; i++)
for (var i = 0; i < properties.Count; i++)
{ {
if (properties[i].property == null) if (properties[i].property == null)
continue; continue;
var partGetter = partGetters[i];
var propertyName = properties[i].Item1.Name;
handlers.Add((partGetter, propertyName));
// for indexers add also a handler for the specific index
if (properties[i].Item3 is not null)
{
handlers.Add((partGetter, $"{propertyName}[{properties[i].Item3}]"));
}
}
yield return Create(Ldc_I4, handlers.Count);
yield return Create(Newarr, tupleRef);
for (var i = 0; i < handlers.Count; i++)
{
yield return Create(Dup); yield return Create(Dup);
yield return Create(Ldc_I4, i); yield return Create(Ldc_I4, i);
yield return Create(Ldnull); yield return Create(Ldnull);
yield return Create(Ldftn, partGetters[i]); yield return Create(Ldftn, handlers[i].PartGetter);
yield return Create(Newobj, module.ImportReference(funcCtor)); yield return Create(Newobj, module.ImportReference(funcCtor));
if (properties[i].Item3 == null) //no indexer yield return Create(Ldstr, handlers[i].PropertyName);
yield return Create(Ldstr, properties[i].Item1.Name);
else
yield return Create(Ldstr, $"{properties[i].Item1.Name}[{properties[i].Item3}]");
yield return Create(Newobj, module.ImportReference(tupleCtor)); yield return Create(Newobj, module.ImportReference(tupleCtor));
yield return Create(Stelem_Ref); yield return Create(Stelem_Ref);
} }

Просмотреть файл

@ -428,29 +428,34 @@ namespace Microsoft.Maui.Controls.Handlers.Items
var item = args.Item; var item = args.Item;
if (args.Mode == ScrollToMode.Position) if (args.Mode == ScrollToMode.Position)
{ {
item = FindBoundItem(args); // Do not use `IGroupableItemsViewSource` since `UngroupedItemsSource` also implements that interface
if (ItemsViewAdapter.ItemsSource is UngroupedItemsSource)
{
return args.Index;
}
else if (ItemsViewAdapter.ItemsSource is IGroupableItemsViewSource groupItemSource)
{
item = FindBoundItemInGroup(args, groupItemSource);
}
} }
return ItemsViewAdapter.GetPositionForItem(item); return ItemsViewAdapter.GetPositionForItem(item);
} }
private object FindBoundItem(ScrollToRequestEventArgs args) private static object FindBoundItemInGroup(ScrollToRequestEventArgs args, IGroupableItemsViewSource groupItemSource)
{ {
if (args.Index >= ItemsViewAdapter.ItemsSource.Count) if (args.GroupIndex >= 0 &&
{
return null;
}
if (ItemsViewAdapter.ItemsSource is IGroupableItemsViewSource groupItemSource &&
args.GroupIndex >= 0 &&
args.GroupIndex < groupItemSource.Count) args.GroupIndex < groupItemSource.Count)
{ {
var group = groupItemSource.GetGroupItemsViewSource(args.GroupIndex); var group = groupItemSource.GetGroupItemsViewSource(args.GroupIndex);
// NOTE: GetItem calls AdjustIndexRequest, which subtracts 1 if we have a header if (group is not null)
return group.GetItem(args.Index + 1); {
// GetItem calls AdjustIndexRequest, which subtracts 1 if we have a header (UngroupedItemsSource does not do this)
return group.GetItem(args.Index + 1);
}
} }
return ItemsViewAdapter.ItemsSource.GetItem(args.Index); return groupItemSource.GetItem(args.Index);
} }
protected virtual void UpdateItemSpacing() protected virtual void UpdateItemSpacing()

Просмотреть файл

@ -79,6 +79,7 @@ namespace Microsoft.Maui.Controls.Platform
Foreground = textColor?.ToPlatform(), Foreground = textColor?.ToPlatform(),
}; };
run.Foreground = textColor?.ToPlatform();
textBlock.TextHighlighters.Add(textHighlighter); textBlock.TextHighlighters.Add(textHighlighter);
} }

Просмотреть файл

@ -172,6 +172,65 @@ namespace Microsoft.Maui.DeviceTests
#if IOS || MACCATALYST || WINDOWS #if IOS || MACCATALYST || WINDOWS
Skip = "Fails: https://github.com/dotnet/maui/issues/17664" Skip = "Fails: https://github.com/dotnet/maui/issues/17664"
#endif #endif
)]
public async Task CollectionScrollToUngroupedWorks()
{
SetupBuilder();
var dataList = new List<TestData>();
string letters = "abcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < letters.Length; i++)
{
dataList.Add(new TestData
{
Name = $"{letters[i]}"
});
}
var collectionView = new CollectionView
{
IsGrouped = false,
ItemsSource = dataList,
ItemTemplate = new DataTemplate(() =>
{
var name = new Label()
{
TextColor = Colors.Grey,
HeightRequest = 64
};
name.SetBinding(Label.TextProperty, "Name");
return name;
})
};
await CreateHandlerAndAddToWindow<CollectionViewHandler>(collectionView, async handler =>
{
collectionView.ScrollTo(index: 24, animate: false); // Item "x"
int retryCount = 3;
bool foundItem = false;
while (retryCount > 0 && !foundItem)
{
retryCount--;
await Task.Delay(500);
for (int i = 0; i < collectionView.LogicalChildrenInternal.Count; i++)
{
var item = collectionView.LogicalChildrenInternal[i];
if (item is Label label && label.Text.Equals("x", StringComparison.OrdinalIgnoreCase))
{
foundItem = true;
break;
}
}
}
Assert.True(foundItem);
});
}
[Fact(
#if IOS || MACCATALYST
Skip = "Fails on iOS/macOS: https://github.com/dotnet/maui/issues/17664"
#endif
)] )]
public async Task CollectionScrollToGroupWorks() public async Task CollectionScrollToGroupWorks()
{ {

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 8.9 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 40 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 15 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 16 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 40 KiB

Просмотреть файл

@ -0,0 +1,24 @@
using Microsoft.Maui.Controls;
namespace Maui.Controls.Sample.Issues
{
[Issue(IssueTracker.Github, 10645, "Image is not centered in AspectFill mode", PlatformAffected.UWP)]
public class Issue10645 : TestContentPage
{
protected override void Init()
{
Content =
new Grid()
{
new Image()
{
AutomationId = "AspectFillImage",
Aspect = Microsoft.Maui.Aspect.AspectFill,
WidthRequest = 100,
HeightRequest = 200,
Source = "dotnet_bot.png",
}
};
}
}
}

Просмотреть файл

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue18720"
xmlns:controls="clr-namespace:Maui.Controls.Sample.Issues">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Button">
<Setter Property="HeightRequest" Value="36" />
<Setter Property="FontSize" Value="9" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<VerticalStackLayout
x:Name="TestLayout">
<Label
Text="BackgroundColor" />
<Entry
x:Name="BackgroundColorEntry"/>
<Button
x:Name="UpdateBackgroundColorButton"
Text="Update Background Color"
Clicked="OnUpdateBackgroundColorButtonClicked"/>
<Button
x:Name="ClearBackgroundColorButton"
Text="Clear Background Color"
Clicked="OnClearBackgroundColorButtonClicked"/>
<Label
Text="Background" />
<Entry
x:Name="BackgroundEntry"/>
<Button
x:Name="UpdateBackgroundButton"
Text="Update Background"
Clicked="OnUpdateBackgroundButtonClicked"/>
<Button
x:Name="ClearBackgroundButton"
Text="Clear Background"
Clicked="OnClearBackgroundButtonClicked"/>
<Button
x:Name="TestButton"
AutomationId="TestButton"
Text="Test"
Margin="0, 12"
Clicked="OnTestButtonClicked"/>
</VerticalStackLayout>
<Label
Text="Custom Entry (Null Android Background)" />
<controls:Issue18720Entry1
AutomationId="CustomEntry1"/>
<Label
Text="Custom Entry (Custom Android Drawable)" />
<controls:Issue18720Entry2
AutomationId="CustomEntry2"/>
</VerticalStackLayout>
</ContentPage>

Просмотреть файл

@ -0,0 +1,117 @@
using System;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Xaml;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Hosting;
namespace Maui.Controls.Sample.Issues
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[Issue(IssueTracker.Github, 18720, "Setting the background property of AppCompatEditText (Entry) in a handler mapping does not work", PlatformAffected.Android)]
public partial class Issue18720 : ContentPage
{
public Issue18720()
{
InitializeComponent();
UpdateEntryBackgroundColor();
UpdateEntryBackground();
}
void OnUpdateBackgroundColorButtonClicked(object sender, System.EventArgs e)
{
UpdateEntryBackgroundColor();
}
void OnClearBackgroundColorButtonClicked(object sender, System.EventArgs e)
{
BackgroundColorEntry.BackgroundColor = null;
}
void OnUpdateBackgroundButtonClicked(object sender, System.EventArgs e)
{
UpdateEntryBackground();
}
void OnClearBackgroundButtonClicked(object sender, System.EventArgs e)
{
BackgroundEntry.Background = null;
}
void OnTestButtonClicked(object sender, EventArgs e)
{
TestLayout.IsVisible = false;
}
void UpdateEntryBackgroundColor()
{
Random rnd = new Random();
Color backgroundColor = Color.FromRgba(rnd.Next(256), rnd.Next(256), rnd.Next(256), 255);
BackgroundColorEntry.BackgroundColor = backgroundColor;
}
void UpdateEntryBackground()
{
Random rnd = new Random();
Color startColor = Color.FromRgba(rnd.Next(256), rnd.Next(256), rnd.Next(256), 255);
Color endColor = Color.FromRgba(rnd.Next(256), rnd.Next(256), rnd.Next(256), 255);
BackgroundEntry.Background = new LinearGradientBrush
{
EndPoint = new Point(1, 0),
GradientStops = new GradientStopCollection
{
new GradientStop { Color = startColor },
new GradientStop { Color = endColor, Offset = 1 }
}
};
}
}
public class Issue18720Entry1 : Entry
{
}
public class Issue18720Entry2 : Entry
{
}
public static class Issue18720Extensions
{
public static MauiAppBuilder Issue18720AddMappers(this MauiAppBuilder builder)
{
builder.ConfigureMauiHandlers(handlers =>
{
Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping(nameof(Issue18720Entry1), (handler, view) =>
{
if (view is Issue18720Entry1)
{
#if ANDROID
handler.PlatformView.Background = null;
handler.PlatformView.SetBackgroundColor(Android.Graphics.Color.Pink);
handler.PlatformView.SetTextColor(Android.Graphics.Color.WhiteSmoke);
#endif
}
});
Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping(nameof(Issue18720Entry2), (handler, view) =>
{
if (view is Issue18720Entry2)
{
#if ANDROID
Android.Graphics.Drawables.GradientDrawable gd = new Android.Graphics.Drawables.GradientDrawable();
gd.SetCornerRadius(10);
gd.SetStroke(2, Android.Graphics.Color.Violet);
handler.PlatformView.Background = gd;
handler.PlatformView.SetTextColor(Android.Graphics.Color.DeepPink);
#endif
}
});
});
return builder;
}
}
}

Просмотреть файл

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue18720DatePicker"
xmlns:controls="clr-namespace:Maui.Controls.Sample.Issues">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Button">
<Setter Property="HeightRequest" Value="36" />
<Setter Property="FontSize" Value="9" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<VerticalStackLayout
x:Name="TestLayout">
<Label
Text="BackgroundColor" />
<DatePicker
x:Name="BackgroundColorDatePicker"/>
<Button
x:Name="UpdateBackgroundColorButton"
Text="Update Background Color"
Clicked="OnUpdateBackgroundColorButtonClicked"/>
<Button
x:Name="ClearBackgroundColorButton"
Text="Clear Background Color"
Clicked="OnClearBackgroundColorButtonClicked"/>
<Label
Text="Background" />
<DatePicker
x:Name="BackgroundDatePicker"/>
<Button
x:Name="UpdateBackgroundButton"
Text="Update Background"
Clicked="OnUpdateBackgroundButtonClicked"/>
<Button
x:Name="ClearBackgroundButton"
Text="Clear Background"
Clicked="OnClearBackgroundButtonClicked"/>
<Button
x:Name="TestButton"
AutomationId="TestButton"
Text="Test"
Margin="0, 12"
Clicked="OnTestButtonClicked"/>
</VerticalStackLayout>
<Label
Text="Custom DatePicker (Null Android Background)" />
<controls:Issue18720DatePicker1
AutomationId="CustomDatePicker1"/>
<Label
Text="Custom DatePicker (Custom Android Drawable)" />
<controls:Issue18720DatePicker2
AutomationId="CustomDatePicker2"/>
</VerticalStackLayout>
</ContentPage>

Просмотреть файл

@ -0,0 +1,117 @@
using System;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Xaml;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Hosting;
namespace Maui.Controls.Sample.Issues
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[Issue(IssueTracker.ManualTest, "18720 DatePicker", "Setting the background property of AppCompatEditText (DatePicker) in a handler mapping does not work", PlatformAffected.Android)]
public partial class Issue18720DatePicker : ContentPage
{
public Issue18720DatePicker()
{
InitializeComponent();
UpdateDatePickerBackgroundColor();
UpdateDatePickerBackground();
}
void OnUpdateBackgroundColorButtonClicked(object sender, EventArgs e)
{
UpdateDatePickerBackgroundColor();
}
void OnClearBackgroundColorButtonClicked(object sender, EventArgs e)
{
BackgroundColorDatePicker.BackgroundColor = null;
}
void OnUpdateBackgroundButtonClicked(object sender, EventArgs e)
{
UpdateDatePickerBackground();
}
void OnClearBackgroundButtonClicked(object sender, EventArgs e)
{
BackgroundDatePicker.Background = null;
}
void OnTestButtonClicked(object sender, EventArgs e)
{
TestLayout.IsVisible = false;
}
void UpdateDatePickerBackgroundColor()
{
Random rnd = new Random();
Color backgroundColor = Color.FromRgba(rnd.Next(256), rnd.Next(256), rnd.Next(256), 255);
BackgroundColorDatePicker.BackgroundColor = backgroundColor;
}
void UpdateDatePickerBackground()
{
Random rnd = new Random();
Color startColor = Color.FromRgba(rnd.Next(256), rnd.Next(256), rnd.Next(256), 255);
Color endColor = Color.FromRgba(rnd.Next(256), rnd.Next(256), rnd.Next(256), 255);
BackgroundDatePicker.Background = new LinearGradientBrush
{
EndPoint = new Point(1, 0),
GradientStops = new GradientStopCollection
{
new GradientStop { Color = startColor },
new GradientStop { Color = endColor, Offset = 1 }
}
};
}
}
public class Issue18720DatePicker1 : DatePicker
{
}
public class Issue18720DatePicker2 : DatePicker
{
}
public static class Issue18720DatePickerExtensions
{
public static MauiAppBuilder Issue18720DatePickerAddMappers(this MauiAppBuilder builder)
{
builder.ConfigureMauiHandlers(handlers =>
{
Microsoft.Maui.Handlers.DatePickerHandler.Mapper.AppendToMapping(nameof(Issue18720DatePicker1), (handler, view) =>
{
if (view is Issue18720DatePicker1)
{
#if ANDROID
handler.PlatformView.Background = null;
handler.PlatformView.SetBackgroundColor(Android.Graphics.Color.Pink);
handler.PlatformView.SetTextColor(Android.Graphics.Color.WhiteSmoke);
#endif
}
});
Microsoft.Maui.Handlers.DatePickerHandler.Mapper.AppendToMapping(nameof(Issue18720DatePicker2), (handler, view) =>
{
if (view is Issue18720DatePicker2)
{
#if ANDROID
Android.Graphics.Drawables.GradientDrawable gd = new Android.Graphics.Drawables.GradientDrawable();
gd.SetCornerRadius(10);
gd.SetStroke(2, Android.Graphics.Color.Violet);
handler.PlatformView.Background = gd;
handler.PlatformView.SetTextColor(Android.Graphics.Color.DeepPink);
#endif
}
});
});
return builder;
}
}
}

Просмотреть файл

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue18720Editor"
xmlns:controls="clr-namespace:Maui.Controls.Sample.Issues">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Button">
<Setter Property="HeightRequest" Value="36" />
<Setter Property="FontSize" Value="9" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<VerticalStackLayout
x:Name="TestLayout">
<Label
Text="BackgroundColor" />
<Editor
x:Name="BackgroundColorEditor"/>
<Button
x:Name="UpdateBackgroundColorButton"
Text="Update Background Color"
Clicked="OnUpdateBackgroundColorButtonClicked"/>
<Button
x:Name="ClearBackgroundColorButton"
Text="Clear Background Color"
Clicked="OnClearBackgroundColorButtonClicked"/>
<Label
Text="Background" />
<Editor
x:Name="BackgroundEditor"/>
<Button
x:Name="UpdateBackgroundButton"
Text="Update Background"
Clicked="OnUpdateBackgroundButtonClicked"/>
<Button
x:Name="ClearBackgroundButton"
Text="Clear Background"
Clicked="OnClearBackgroundButtonClicked"/>
<Button
x:Name="TestButton"
AutomationId="TestButton"
Text="Test"
Margin="0, 12"
Clicked="OnTestButtonClicked"/>
</VerticalStackLayout>
<Label
Text="Custom Editor (Null Android Background)" />
<controls:Issue18720Editor1
AutomationId="CustomEditor1"/>
<Label
Text="Custom Editor (Custom Android Drawable)" />
<controls:Issue18720Editor2
AutomationId="CustomEditor2"/>
</VerticalStackLayout>
</ContentPage>

Просмотреть файл

@ -0,0 +1,117 @@
using System;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Xaml;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Hosting;
namespace Maui.Controls.Sample.Issues
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[Issue(IssueTracker.Github, "18720 Editor", "Setting the background property of AppCompatEditText (Editor) in a handler mapping does not work", PlatformAffected.Android)]
public partial class Issue18720Editor : ContentPage
{
public Issue18720Editor()
{
InitializeComponent();
UpdateEditorBackgroundColor();
UpdateEditorBackground();
}
void OnUpdateBackgroundColorButtonClicked(object sender, System.EventArgs e)
{
UpdateEditorBackgroundColor();
}
void OnClearBackgroundColorButtonClicked(object sender, System.EventArgs e)
{
BackgroundColorEditor.BackgroundColor = null;
}
void OnUpdateBackgroundButtonClicked(object sender, System.EventArgs e)
{
UpdateEditorBackground();
}
void OnClearBackgroundButtonClicked(object sender, System.EventArgs e)
{
BackgroundEditor.Background = null;
}
void OnTestButtonClicked(object sender, EventArgs e)
{
TestLayout.IsVisible = false;
}
void UpdateEditorBackgroundColor()
{
Random rnd = new Random();
Color backgroundColor = Color.FromRgba(rnd.Next(256), rnd.Next(256), rnd.Next(256), 255);
BackgroundColorEditor.BackgroundColor = backgroundColor;
}
void UpdateEditorBackground()
{
Random rnd = new Random();
Color startColor = Color.FromRgba(rnd.Next(256), rnd.Next(256), rnd.Next(256), 255);
Color endColor = Color.FromRgba(rnd.Next(256), rnd.Next(256), rnd.Next(256), 255);
BackgroundEditor.Background = new LinearGradientBrush
{
EndPoint = new Point(1, 0),
GradientStops = new GradientStopCollection
{
new GradientStop { Color = startColor },
new GradientStop { Color = endColor, Offset = 1 }
}
};
}
}
public class Issue18720Editor1 : Editor
{
}
public class Issue18720Editor2 : Editor
{
}
public static class Issue18720EditorExtensions
{
public static MauiAppBuilder Issue18720EditorAddMappers(this MauiAppBuilder builder)
{
builder.ConfigureMauiHandlers(handlers =>
{
Microsoft.Maui.Handlers.EditorHandler.Mapper.AppendToMapping(nameof(Issue18720Editor1), (handler, view) =>
{
if (view is Issue18720Editor1)
{
#if ANDROID
handler.PlatformView.Background = null;
handler.PlatformView.SetBackgroundColor(Android.Graphics.Color.Pink);
handler.PlatformView.SetTextColor(Android.Graphics.Color.WhiteSmoke);
#endif
}
});
Microsoft.Maui.Handlers.EditorHandler.Mapper.AppendToMapping(nameof(Issue18720Editor2), (handler, view) =>
{
if (view is Issue18720Editor2)
{
#if ANDROID
Android.Graphics.Drawables.GradientDrawable gd = new Android.Graphics.Drawables.GradientDrawable();
gd.SetCornerRadius(10);
gd.SetStroke(2, Android.Graphics.Color.Violet);
handler.PlatformView.Background = gd;
handler.PlatformView.SetTextColor(Android.Graphics.Color.DeepPink);
#endif
}
});
});
return builder;
}
}
}

Просмотреть файл

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue18720TimePicker"
xmlns:controls="clr-namespace:Maui.Controls.Sample.Issues">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Button">
<Setter Property="HeightRequest" Value="36" />
<Setter Property="FontSize" Value="9" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<VerticalStackLayout
x:Name="TestLayout">
<Label
Text="BackgroundColor" />
<TimePicker
x:Name="BackgroundColorTimePicker"/>
<Button
x:Name="UpdateBackgroundColorButton"
Text="Update Background Color"
Clicked="OnUpdateBackgroundColorButtonClicked"/>
<Button
x:Name="ClearBackgroundColorButton"
Text="Clear Background Color"
Clicked="OnClearBackgroundColorButtonClicked"/>
<Label
Text="Background" />
<TimePicker
x:Name="BackgroundTimePicker"/>
<Button
x:Name="UpdateBackgroundButton"
Text="Update Background"
Clicked="OnUpdateBackgroundButtonClicked"/>
<Button
x:Name="ClearBackgroundButton"
Text="Clear Background"
Clicked="OnClearBackgroundButtonClicked"/>
<Button
x:Name="TestButton"
AutomationId="TestButton"
Text="Test"
Margin="0, 12"
Clicked="OnTestButtonClicked"/>
</VerticalStackLayout>
<Label
Text="Custom TimePicker (Null Android Background)" />
<controls:Issue18720TimePicker1
AutomationId="CustomTimePicker1"/>
<Label
Text="Custom TimePicker (Custom Android Drawable)" />
<controls:Issue18720TimePicker2
AutomationId="CustomTimePicker2"/>
</VerticalStackLayout>
</ContentPage>

Просмотреть файл

@ -0,0 +1,117 @@
using System;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Xaml;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Hosting;
namespace Maui.Controls.Sample.Issues
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[Issue(IssueTracker.ManualTest, "18720 TimePicker", "Setting the background property of AppCompatEditText (TimePicker) in a handler mapping does not work", PlatformAffected.Android)]
public partial class Issue18720TimePicker : ContentPage
{
public Issue18720TimePicker()
{
InitializeComponent();
UpdateTimePickerBackgroundColor();
UpdateTimePickerBackground();
}
void OnUpdateBackgroundColorButtonClicked(object sender, EventArgs e)
{
UpdateTimePickerBackgroundColor();
}
void OnClearBackgroundColorButtonClicked(object sender, EventArgs e)
{
BackgroundColorTimePicker.BackgroundColor = null;
}
void OnUpdateBackgroundButtonClicked(object sender, EventArgs e)
{
UpdateTimePickerBackground();
}
void OnClearBackgroundButtonClicked(object sender, EventArgs e)
{
BackgroundTimePicker.Background = null;
}
void OnTestButtonClicked(object sender, EventArgs e)
{
TestLayout.IsVisible = false;
}
void UpdateTimePickerBackgroundColor()
{
Random rnd = new Random();
Color backgroundColor = Color.FromRgba(rnd.Next(256), rnd.Next(256), rnd.Next(256), 255);
BackgroundColorTimePicker.BackgroundColor = backgroundColor;
}
void UpdateTimePickerBackground()
{
Random rnd = new Random();
Color startColor = Color.FromRgba(rnd.Next(256), rnd.Next(256), rnd.Next(256), 255);
Color endColor = Color.FromRgba(rnd.Next(256), rnd.Next(256), rnd.Next(256), 255);
BackgroundTimePicker.Background = new LinearGradientBrush
{
EndPoint = new Point(1, 0),
GradientStops = new GradientStopCollection
{
new GradientStop { Color = startColor },
new GradientStop { Color = endColor, Offset = 1 }
}
};
}
}
public class Issue18720TimePicker1 : TimePicker
{
}
public class Issue18720TimePicker2 : TimePicker
{
}
public static class Issue18720TimePickerExtensions
{
public static MauiAppBuilder Issue18720TimePickerAddMappers(this MauiAppBuilder builder)
{
builder.ConfigureMauiHandlers(handlers =>
{
Microsoft.Maui.Handlers.TimePickerHandler.Mapper.AppendToMapping(nameof(Issue18720TimePicker1), (handler, view) =>
{
if (view is Issue18720TimePicker1)
{
#if ANDROID
handler.PlatformView.Background = null;
handler.PlatformView.SetBackgroundColor(Android.Graphics.Color.Pink);
handler.PlatformView.SetTextColor(Android.Graphics.Color.WhiteSmoke);
#endif
}
});
Microsoft.Maui.Handlers.TimePickerHandler.Mapper.AppendToMapping(nameof(Issue18720TimePicker2), (handler, view) =>
{
if (view is Issue18720TimePicker2)
{
#if ANDROID
Android.Graphics.Drawables.GradientDrawable gd = new Android.Graphics.Drawables.GradientDrawable();
gd.SetCornerRadius(10);
gd.SetStroke(2, Android.Graphics.Color.Violet);
handler.PlatformView.Background = gd;
handler.PlatformView.SetTextColor(Android.Graphics.Color.DeepPink);
#endif
}
});
});
return builder;
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue23488">
<StackLayout HorizontalOptions="Center"
VerticalOptions="Center">
<Label Text="hyperlink"
TextColor="Blue"
TextDecorations="Underline" />
<Label AutomationId="WaitForLabelControl">
<Label.FormattedText>
<FormattedString>
<Span Text="hyperlink"
TextColor="Blue"
TextDecorations="Underline" />
</FormattedString>
</Label.FormattedText>
</Label>
</StackLayout>
</ContentPage>

Просмотреть файл

@ -0,0 +1,12 @@
namespace Maui.Controls.Sample.Issues
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[Issue(IssueTracker.Github, 23488, "Span text-decoration is incorrect whereas the Label behaves properly", PlatformAffected.UWP)]
public partial class Issue23488 : ContentPage
{
public Issue23488()
{
InitializeComponent();
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
using System; using System;
using Maui.Controls.Sample.Issues; using Maui.Controls.Sample.Issues;
using Microsoft.Maui; using Microsoft.Maui;
using Microsoft.Maui.Controls; using Microsoft.Maui.Controls;
@ -23,7 +23,11 @@ namespace Maui.Controls.Sample
fonts.AddFont("FontAwesome.ttf", "FA"); fonts.AddFont("FontAwesome.ttf", "FA");
fonts.AddFont("ionicons.ttf", "Ion"); fonts.AddFont("ionicons.ttf", "Ion");
}) })
.Issue21109AddMappers(); .Issue21109AddMappers()
.Issue18720AddMappers()
.Issue18720EditorAddMappers()
.Issue18720DatePickerAddMappers()
.Issue18720TimePickerAddMappers();
appBuilder.Services.AddTransient<TransientPage>(); appBuilder.Services.AddTransient<TransientPage>();
appBuilder.Services.AddScoped<ScopedPage>(); appBuilder.Services.AddScoped<ScopedPage>();

Просмотреть файл

@ -0,0 +1,26 @@
#if WINDOWS
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue10645 : _IssuesUITest
{
public Issue10645(TestDevice device) : base(device)
{
}
public override string Issue => "Image is not centered in AspectFill mode";
[Test]
[Category(UITestCategories.ActionSheet)]
public void Issue10645Test()
{
App.WaitForElement("AspectFillImage", timeout: TimeSpan.FromSeconds(4));
VerifyScreenshot();
}
}
}
#endif

Просмотреть файл

@ -0,0 +1,30 @@
#if ANDROID
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue18720 : _IssuesUITest
{
public Issue18720(TestDevice device) : base(device)
{
}
public override string Issue => "Setting the background property of AppCompatEditText (Entry) in a handler mapping does not work";
[Test]
[Category(UITestCategories.Entry)]
public async Task SettingEntryBackgroundFromHandler()
{
App.WaitForElement("TestButton");
App.Tap("TestButton");
App.WaitForElement("CustomEntry1");
await Task.Delay(500);
VerifyScreenshot();
}
}
}
#endif

Просмотреть файл

@ -0,0 +1,30 @@
#if ANDROID
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue18720DatePicker : _IssuesUITest
{
public Issue18720DatePicker(TestDevice device) : base(device)
{
}
public override string Issue => "Setting the background property of AppCompatEditText (DatePicker) in a handler mapping does not work";
[Test]
[Category(UITestCategories.DatePicker)]
public async Task SettingDatePickerBackgroundFromHandler()
{
App.WaitForElement("TestButton");
App.Tap("TestButton");
App.WaitForElement("CustomDatePicker1");
await Task.Delay(500);
VerifyScreenshot();
}
}
}
#endif

Просмотреть файл

@ -0,0 +1,30 @@
#if ANDROID
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue18720Editor : _IssuesUITest
{
public Issue18720Editor(TestDevice device) : base(device)
{
}
public override string Issue => "Setting the background property of AppCompatEditText (Editor) in a handler mapping does not work";
[Test]
[Category(UITestCategories.Editor)]
public async Task SettingEditorBackgroundFromHandler()
{
App.WaitForElement("TestButton");
App.Tap("TestButton");
App.WaitForElement("CustomEditor1");
await Task.Delay(500);
VerifyScreenshot();
}
}
}
#endif

Просмотреть файл

@ -0,0 +1,30 @@
#if ANDROID
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue18720TimePicker : _IssuesUITest
{
public Issue18720TimePicker(TestDevice device) : base(device)
{
}
public override string Issue => "Setting the background property of AppCompatEditText (TimePicker) in a handler mapping does not work";
[Test]
[Category(UITestCategories.TimePicker)]
public async Task SettingTimePickerBackgroundFromHandler()
{
App.WaitForElement("TestButton");
App.Tap("TestButton");
App.WaitForElement("CustomTimePicker1");
await Task.Delay(500);
VerifyScreenshot();
}
}
}
#endif

Просмотреть файл

@ -0,0 +1,25 @@
#if !MACCATALYST
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue23488 : _IssuesUITest
{
public Issue23488(TestDevice device): base(device)
{
}
public override string Issue => "Span text-decoration is incorrect whereas the Label behaves properly";
[Test]
[Category(UITestCategories.Label)]
public void LabelHyperlinkUnderlineColor()
{
App.WaitForElement("WaitForLabelControl");
VerifyScreenshot();
}
}
}
#endif

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 24 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.5 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Просмотреть файл

@ -98,6 +98,10 @@ namespace Microsoft.Maui.Controls.Xaml.UnitTests
vm.Model[3] = "TextIndex2"; vm.Model[3] = "TextIndex2";
Assert.AreEqual("TextIndex2", layout.label3.Text); Assert.AreEqual("TextIndex2", layout.label3.Text);
//https://github.com/dotnet/maui/issues/23621
vm.Model.SetIndexerValueAndCallOnPropertyChangedWithoutIndex(3, "TextIndex3");
Assert.AreEqual("TextIndex3", layout.label3.Text);
//testing 2way //testing 2way
Assert.AreEqual("Text2", layout.entry0.Text); Assert.AreEqual("Text2", layout.entry0.Text);
((IElementController)layout.entry0).SetValueFromRenderer(Entry.TextProperty, "Text3"); ((IElementController)layout.entry0).SetValueFromRenderer(Entry.TextProperty, "Text3");
@ -235,6 +239,15 @@ namespace Microsoft.Maui.Controls.Xaml.UnitTests
{ {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
} }
public void SetIndexerValueAndCallOnPropertyChangedWithoutIndex(int v, string value)
{
if (values[v] == value)
return;
values[v] = value;
OnPropertyChanged("Indexer");
}
} }
class MockItemViewModel : INotifyPropertyChanged class MockItemViewModel : INotifyPropertyChanged

Просмотреть файл

@ -136,7 +136,12 @@ namespace Microsoft.Maui
var visualElements = new List<IVisualTreeElement>(); var visualElements = new List<IVisualTreeElement>();
if (visualElement is IWindow window) if (visualElement is IWindow window)
{ {
uiElement = window.Content?.ToPlatform(); // Get the UI.Xaml.Window so we catch everything in the app window rather than the frame which doesn't include modal content
var platformView = window.Handler?.PlatformView;
if (platformView is UI.Xaml.Window winUiWindow)
{
uiElement = winUiWindow.Content;
}
} }
else if (visualElement is IView view) else if (visualElement is IView view)
{ {

Просмотреть файл

@ -8,8 +8,10 @@ namespace Microsoft.Maui.Handlers
{ {
public partial class ImageHandler : ViewHandler<IImage, WImage> public partial class ImageHandler : ViewHandler<IImage, WImage>
{ {
/// <inheritdoc/>
protected override WImage CreatePlatformView() => new WImage(); protected override WImage CreatePlatformView() => new WImage();
/// <inheritdoc/>
protected override void ConnectHandler(WImage platformView) protected override void ConnectHandler(WImage platformView)
{ {
platformView.ImageOpened += OnImageOpened; platformView.ImageOpened += OnImageOpened;
@ -17,6 +19,7 @@ namespace Microsoft.Maui.Handlers
base.ConnectHandler(platformView); base.ConnectHandler(platformView);
} }
/// <inheritdoc/>
protected override void DisconnectHandler(WImage platformView) protected override void DisconnectHandler(WImage platformView)
{ {
platformView.ImageOpened -= OnImageOpened; platformView.ImageOpened -= OnImageOpened;
@ -25,25 +28,113 @@ namespace Microsoft.Maui.Handlers
SourceLoader.Reset(); SourceLoader.Reset();
} }
/// <inheritdoc/>
public override bool NeedsContainer => public override bool NeedsContainer =>
VirtualView?.Background != null || VirtualView?.Background != null ||
VirtualView?.Aspect == Aspect.AspectFill ||
base.NeedsContainer; base.NeedsContainer;
/// <inheritdoc/>
protected override void SetupContainer()
{
base.SetupContainer();
// VerticalAlignment only works when the child's Height is Auto
PlatformView.Height = Primitives.Dimension.Unset;
UpdateValue(nameof(IView.Height));
UpdateValue(nameof(IView.Width));
}
/// <inheritdoc/>
protected override void RemoveContainer()
{
base.RemoveContainer();
UpdateValue(nameof(IView.Height));
UpdateValue(nameof(IView.Width));
}
/// <summary>
/// Maps the abstract <see cref="IView.Height"/> property to the platform-specific implementations.
/// </summary>
/// <param name="handler">The associated handler.</param>
/// <param name="view">The associated <see cref="Image"/> instance.</param>
public static void MapHeight(IImageHandler handler, IImage view)
{
// VerticalAlignment only works when the container's Height is set and the child's Height is Auto. The child's Height
// is set to Auto when the container is introduced.
if (handler.ContainerView is FrameworkElement container)
{
container.Height = view.Height;
handler.PlatformView.Height = Primitives.Dimension.Unset;
}
else
{
ViewHandler.MapHeight(handler, view);
}
}
/// <summary>
/// Maps the abstract <see cref="IView.Width"/> property to the platform-specific implementations.
/// </summary>
/// <param name="handler">The associated handler.</param>
/// <param name="view">The associated <see cref="Image"/> instance.</param>
public static void MapWidth(IImageHandler handler, IImage view)
{
if (handler.ContainerView is FrameworkElement container)
{
container.Width = view.Width;
}
else
{
ViewHandler.MapWidth(handler, view);
}
}
/// <summary>
/// Maps the abstract <see cref="IView.Background"/> property to the platform-specific implementations.
/// </summary>
/// <param name="handler">The associated handler.</param>
/// <param name="image">The associated <see cref="Image"/> instance.</param>
public static void MapBackground(IImageHandler handler, IImage image) public static void MapBackground(IImageHandler handler, IImage image)
{ {
handler.UpdateValue(nameof(IViewHandler.ContainerView)); handler.UpdateValue(nameof(IViewHandler.ContainerView));
handler.ToPlatform().UpdateBackground(image); handler.ToPlatform().UpdateBackground(image);
} }
public static void MapAspect(IImageHandler handler, IImage image) => /// <summary>
/// Maps the abstract <see cref="IImage.Aspect"/> property to the platform-specific implementations.
/// </summary>
/// <param name="handler">The associated handler.</param>
/// <param name="image">The associated <see cref="Image"/> instance.</param>
public static void MapAspect(IImageHandler handler, IImage image)
{
handler.UpdateValue(nameof(IViewHandler.ContainerView));
handler.PlatformView?.UpdateAspect(image); handler.PlatformView?.UpdateAspect(image);
}
/// <summary>
/// Maps the abstract <see cref="IImageSourcePart.IsAnimationPlaying"/> property to the platform-specific implementations.
/// </summary>
/// <param name="handler">The associated handler.</param>
/// <param name="image">The associated <see cref="Image"/> instance.</param>
public static void MapIsAnimationPlaying(IImageHandler handler, IImage image) => public static void MapIsAnimationPlaying(IImageHandler handler, IImage image) =>
handler.PlatformView?.UpdateIsAnimationPlaying(image); handler.PlatformView?.UpdateIsAnimationPlaying(image);
/// <summary>
/// Maps the abstract <see cref="IImageSourcePart.Source"/> property to the platform-specific implementations.
/// </summary>
/// <param name="handler">The associated handler.</param>
/// <param name="image">The associated <see cref="Image"/> instance.</param>
public static void MapSource(IImageHandler handler, IImage image) => public static void MapSource(IImageHandler handler, IImage image) =>
MapSourceAsync(handler, image).FireAndForget(handler); MapSourceAsync(handler, image).FireAndForget(handler);
/// <summary>
/// Maps the abstract <see cref="IImageSourcePart.Source"/> property to the platform-specific implementations as an asynchronous operation.
/// </summary>
/// <param name="handler">The associated handler.</param>
/// <param name="image">The associated <see cref="Image"/> instance.</param>
public static Task MapSourceAsync(IImageHandler handler, IImage image) => public static Task MapSourceAsync(IImageHandler handler, IImage image) =>
handler.SourceLoader.UpdateImageSourceAsync(); handler.SourceLoader.UpdateImageSourceAsync();
@ -66,4 +157,4 @@ namespace Microsoft.Maui.Handlers
} }
} }
} }
} }

Просмотреть файл

@ -20,6 +20,10 @@ namespace Microsoft.Maui.Handlers
{ {
#if __ANDROID__ || WINDOWS || TIZEN #if __ANDROID__ || WINDOWS || TIZEN
[nameof(IImage.Background)] = MapBackground, [nameof(IImage.Background)] = MapBackground,
#endif
#if WINDOWS
[nameof(IImage.Height)] = MapHeight,
[nameof(IImage.Width)] = MapWidth,
#endif #endif
[nameof(IImage.Aspect)] = MapAspect, [nameof(IImage.Aspect)] = MapAspect,
[nameof(IImage.IsAnimationPlaying)] = MapIsAnimationPlaying, [nameof(IImage.IsAnimationPlaying)] = MapIsAnimationPlaying,

Просмотреть файл

@ -0,0 +1,17 @@
using Android.Graphics.Drawables;
using Android.Runtime;
namespace Microsoft.Maui.Platform;
internal class MauiLayerDrawable : LayerDrawable
{
public MauiLayerDrawable(params Drawable[] layers)
: base(layers)
{
}
protected MauiLayerDrawable(nint javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
}

Просмотреть файл

@ -9,10 +9,9 @@ using Android.Views;
using Android.Views.InputMethods; using Android.Views.InputMethods;
using Android.Widget; using Android.Widget;
using AndroidX.AppCompat.Widget; using AndroidX.AppCompat.Widget;
using AndroidX.ConstraintLayout.Helper.Widget;
using AndroidX.Core.Content; using AndroidX.Core.Content;
using AndroidX.Core.View; using AndroidX.Core.View;
using AndroidX.Window.Layout; using Kotlin;
using Microsoft.Maui.ApplicationModel; using Microsoft.Maui.ApplicationModel;
using Microsoft.Maui.Graphics; using Microsoft.Maui.Graphics;
using Microsoft.Maui.Primitives; using Microsoft.Maui.Primitives;
@ -188,62 +187,83 @@ namespace Microsoft.Maui.Platform
internal static void UpdateBackground(this EditText platformView, IView view) internal static void UpdateBackground(this EditText platformView, IView view)
{ {
if (platformView is null || platformView.Background is null || platformView.Context is null) if (platformView is null || platformView.Context is null)
{ {
return; return;
} }
// Remove previous background gradient if any // The user has removed the background from the platform view in platform code
if (platformView.Background is MauiDrawable mauiDrawable) // so we need to make sure to do absolutely nothing.
if (platformView.Background is null)
{ {
platformView.Background = null; return;
mauiDrawable.Dispose();
} }
if (platformView.Background is LayerDrawable layerDrawable) // Get the current background of the edit text so we can make sure to not overwite it
// if it is not something that we have set in MAUI.
var previousDrawable = platformView.Background;
// Remove the previous MAUI background (if any).
if (previousDrawable is MauiDrawable || previousDrawable is MauiLayerDrawable)
{ {
platformView.Background = null; platformView.Background = null;
layerDrawable.Dispose(); previousDrawable.Dispose();
previousDrawable = null;
} }
// Android will reset the padding when setting a Background drawable // Get the new background from the virtual view
// So we need to reapply the padding after
var padLeft = platformView.PaddingLeft;
var padTop = platformView.PaddingTop;
var padRight = platformView.PaddingRight;
var padBottom = platformView.PaddingBottom;
var paint = view.Background; var paint = view.Background;
Drawable? defaultBackgroundDrawable = ContextCompat.GetDrawable(platformView.Context, Resource.Drawable.abc_edit_text_material);
var previousDrawable = defaultBackgroundDrawable ?? platformView.Background;
var backgroundDrawable = paint.ToDrawable(platformView.Context); var backgroundDrawable = paint.ToDrawable(platformView.Context);
if (previousDrawable is null) if (backgroundDrawable is not null || previousDrawable is null)
platformView.Background = backgroundDrawable;
else
{ {
if (backgroundDrawable is null) // There is a new background to set, or we removed a previous background and
{ // now we have to re-apply just the default "line" background.
// The default Drawable of EditText is an InsetDrawable and setting the background we use a LayerDrawable
// to compose the custom background with the default behavior (bottom line).
//
// If the Background is null or is a ColorDrawable, a Custom Handler is being created, removing the default behavior.
// In this case, we don't want to reset the Drawable to the default one.
if (platformView.Background is not ColorDrawable)
platformView.Background = previousDrawable;
}
else
{
LayerDrawable layer = new LayerDrawable(new Drawable[] { backgroundDrawable, previousDrawable }); // Regardless of what the new background is, we will need to apply the default
platformView.Background = layer; // background "line" on top of it.
// If for some reason this returns null, then there is nothing we can do because
// AndroidX is probably broken since this is a resource from the AndroidX library.
var defaultBackground = ContextCompat.GetDrawable(platformView.Context, Resource.Drawable.abc_edit_text_material);
if (backgroundDrawable is not null)
{
// The user set some background, so we need to apply it below the default "line".
// If there is a broken AndroidX, then nothing we can do but just use ours.
SetBackground(platformView, defaultBackground is null
? new MauiLayerDrawable(backgroundDrawable)
: new MauiLayerDrawable(backgroundDrawable, defaultBackground));
}
else if (previousDrawable is null)
{
// The user set null in the virtual view (or did not set anything/kept the defaults)
// as we just removed a MAUI background from the platform view.
// This means we just use the default Material background (the "line").
SetBackground(platformView, defaultBackground);
} }
} }
else
{
// The drawable currently in use was not a MAUI drawable nor are we setting a new
// one so just do nothing and keep whatever the user has set in platform code.
}
// Apply previous padding // A helper method to set the background and re-apply the padding since
platformView.SetPadding(padLeft, padTop, padRight, padBottom); // Android will reset the padding when setting a Background drawable.
static void SetBackground(EditText platformView, Drawable? background)
{
// Cache the current padding
var padLeft = platformView.PaddingLeft;
var padTop = platformView.PaddingTop;
var padRight = platformView.PaddingRight;
var padBottom = platformView.PaddingBottom;
// Set the new background
platformView.Background = background;
// Apply previous padding
platformView.SetPadding(padLeft, padTop, padRight, padBottom);
}
} }
public static void UpdateBackground(this AView platformView, Paint? background) => public static void UpdateBackground(this AView platformView, Paint? background) =>

Просмотреть файл

@ -1,4 +1,5 @@
#nullable enable #nullable enable
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media.Imaging; using Microsoft.UI.Xaml.Media.Imaging;
using WImage = Microsoft.UI.Xaml.Controls.Image; using WImage = Microsoft.UI.Xaml.Controls.Image;
@ -14,6 +15,12 @@ namespace Microsoft.Maui.Platform
public static void UpdateAspect(this WImage imageView, IImage image) public static void UpdateAspect(this WImage imageView, IImage image)
{ {
imageView.Stretch = image.Aspect.ToStretch(); imageView.Stretch = image.Aspect.ToStretch();
if (image.Aspect == Aspect.AspectFill)
{
imageView.VerticalAlignment = VerticalAlignment.Center;
imageView.HorizontalAlignment = HorizontalAlignment.Center;
}
} }
public static void UpdateIsAnimationPlaying(this WImage imageView, IImageSourcePart image) public static void UpdateIsAnimationPlaying(this WImage imageView, IImageSourcePart image)

Просмотреть файл

@ -83,6 +83,8 @@ override Microsoft.Maui.Handlers.HybridWebViewHandler.ConnectHandler(Microsoft.U
override Microsoft.Maui.Handlers.HybridWebViewHandler.CreatePlatformView() -> Microsoft.UI.Xaml.Controls.WebView2! override Microsoft.Maui.Handlers.HybridWebViewHandler.CreatePlatformView() -> Microsoft.UI.Xaml.Controls.WebView2!
override Microsoft.Maui.Handlers.HybridWebViewHandler.DisconnectHandler(Microsoft.UI.Xaml.Controls.WebView2! platformView) -> void override Microsoft.Maui.Handlers.HybridWebViewHandler.DisconnectHandler(Microsoft.UI.Xaml.Controls.WebView2! platformView) -> void
override Microsoft.Maui.Handlers.ImageHandler.ConnectHandler(Microsoft.UI.Xaml.Controls.Image! platformView) -> void override Microsoft.Maui.Handlers.ImageHandler.ConnectHandler(Microsoft.UI.Xaml.Controls.Image! platformView) -> void
override Microsoft.Maui.Handlers.ImageHandler.RemoveContainer() -> void
override Microsoft.Maui.Handlers.ImageHandler.SetupContainer() -> void
override Microsoft.Maui.Handlers.MenuFlyoutHandler.DisconnectHandler(Microsoft.UI.Xaml.Controls.MenuFlyout! platformView) -> void override Microsoft.Maui.Handlers.MenuFlyoutHandler.DisconnectHandler(Microsoft.UI.Xaml.Controls.MenuFlyout! platformView) -> void
override Microsoft.Maui.Layouts.FlexBasis.Equals(object? obj) -> bool override Microsoft.Maui.Layouts.FlexBasis.Equals(object? obj) -> bool
override Microsoft.Maui.Layouts.FlexBasis.GetHashCode() -> int override Microsoft.Maui.Layouts.FlexBasis.GetHashCode() -> int
@ -106,6 +108,8 @@ static Microsoft.Maui.Handlers.HybridWebViewHandler.MapEvaluateJavaScriptAsync(M
static Microsoft.Maui.Handlers.HybridWebViewHandler.Mapper -> Microsoft.Maui.IPropertyMapper<Microsoft.Maui.IHybridWebView!, Microsoft.Maui.Handlers.IHybridWebViewHandler!>! static Microsoft.Maui.Handlers.HybridWebViewHandler.Mapper -> Microsoft.Maui.IPropertyMapper<Microsoft.Maui.IHybridWebView!, Microsoft.Maui.Handlers.IHybridWebViewHandler!>!
static Microsoft.Maui.Handlers.HybridWebViewHandler.MapSendRawMessage(Microsoft.Maui.Handlers.IHybridWebViewHandler! handler, Microsoft.Maui.IHybridWebView! hybridWebView, object? arg) -> void static Microsoft.Maui.Handlers.HybridWebViewHandler.MapSendRawMessage(Microsoft.Maui.Handlers.IHybridWebViewHandler! handler, Microsoft.Maui.IHybridWebView! hybridWebView, object? arg) -> void
static Microsoft.Maui.Handlers.LayoutHandler.MapInputTransparent(Microsoft.Maui.ILayoutHandler! handler, Microsoft.Maui.ILayout! layout) -> void static Microsoft.Maui.Handlers.LayoutHandler.MapInputTransparent(Microsoft.Maui.ILayoutHandler! handler, Microsoft.Maui.ILayout! layout) -> void
static Microsoft.Maui.Handlers.ImageHandler.MapHeight(Microsoft.Maui.Handlers.IImageHandler! handler, Microsoft.Maui.IImage! view) -> void
static Microsoft.Maui.Handlers.ImageHandler.MapWidth(Microsoft.Maui.Handlers.IImageHandler! handler, Microsoft.Maui.IImage! view) -> void
static Microsoft.Maui.Handlers.SearchBarHandler.MapIsSpellCheckEnabled(Microsoft.Maui.Handlers.ISearchBarHandler! handler, Microsoft.Maui.ISearchBar! searchBar) -> void static Microsoft.Maui.Handlers.SearchBarHandler.MapIsSpellCheckEnabled(Microsoft.Maui.Handlers.ISearchBarHandler! handler, Microsoft.Maui.ISearchBar! searchBar) -> void
static Microsoft.Maui.Handlers.SwipeItemMenuItemHandler.MapSourceAsync(Microsoft.Maui.Handlers.ISwipeItemMenuItemHandler! handler, Microsoft.Maui.ISwipeItemMenuItem! image) -> System.Threading.Tasks.Task! static Microsoft.Maui.Handlers.SwipeItemMenuItemHandler.MapSourceAsync(Microsoft.Maui.Handlers.ISwipeItemMenuItemHandler! handler, Microsoft.Maui.ISwipeItemMenuItem! image) -> System.Threading.Tasks.Task!
static Microsoft.Maui.Hosting.MauiHandlersCollectionExtensions.AddHandler<TType>(this Microsoft.Maui.Hosting.IMauiHandlersCollection! handlersCollection, System.Func<System.IServiceProvider!, Microsoft.Maui.IElementHandler!>! handlerImplementationFactory) -> Microsoft.Maui.Hosting.IMauiHandlersCollection! static Microsoft.Maui.Hosting.MauiHandlersCollectionExtensions.AddHandler<TType>(this Microsoft.Maui.Hosting.IMauiHandlersCollection! handlersCollection, System.Func<System.IServiceProvider!, Microsoft.Maui.IElementHandler!>! handlerImplementationFactory) -> Microsoft.Maui.Hosting.IMauiHandlersCollection!