Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6e3eaf8
[macOS] Fix crash using Shell SearchHandler on Catalyst (#11926)
jsuarezruiz Feb 15, 2023
7847d2b
Finalize Essentials API Docs (#13320)
jfversluis Feb 15, 2023
5cbb27e
[iOS] Fix sizing of button when using CharacterSpacing (#13250) Fixes…
rmarinho Feb 15, 2023
0ea3ee2
fix(ShellView): Fixed an issue in `ShellView` where items added via c…
Foda Feb 15, 2023
536fee6
Changes in project template to avoid BoxView mistake (#13348)
jsuarezruiz Feb 15, 2023
e2c96f1
Bump coverlet.collector from 3.1.2 to 3.2.0 (#13359)
dependabot[bot] Feb 15, 2023
7070feb
Bump Microsoft.AspNetCore.Authorization from 7.0.2 to 7.0.3 (#13350)
dependabot[bot] Feb 15, 2023
f4637b3
[Windows] Fix crash using complex html content (#11409)
jsuarezruiz Feb 15, 2023
b126535
[CI] Enure the pwsh is in the right dir. (#13370)
mandel-macaque Feb 16, 2023
de88e02
[create-pull-request] automated change (#13373)
github-actions[bot] Feb 16, 2023
3c631e7
Added pending changes in Android AlertManager (#11989)
jsuarezruiz Feb 16, 2023
549fde4
Update dotnet-autoformat-pr-push.yml (#13390)
rmarinho Feb 16, 2023
8de6896
Ensure OnMeasure always calls SetMeasuredDimension in ShellPageContai…
BioTurboNick Feb 16, 2023
1182230
Clarify test (#13363)
PureWeen Feb 16, 2023
b34ef5e
Bump Microsoft.Web.WebView2 from 1.0.1518.46 to 1.0.1587.40 (#13389)
dependabot[bot] Feb 16, 2023
2a15957
[Android] Fix crash adding items to CollectionView on navigating (#13…
jsuarezruiz Feb 16, 2023
f6d8e15
[iOS/MacCatalyst] Fix Editor scrolling (#13234)
rmarinho Feb 16, 2023
46cfab5
[Windows] Fix Shell FlyoutBackground property (#13132)
jsuarezruiz Feb 17, 2023
0372df7
[core] fix memory leaks in bindings (#13327)
jonathanpeppers Feb 17, 2023
d162c65
[CI] Fix more paths in the packs.yml to work with the unified pipeline.
mandel-macaque Feb 17, 2023
fa8e06c
[CI] Fix more paths in the packs.yml to work with the unified pipelin…
mandel-macaque Feb 17, 2023
8cfa610
[CI] Fix the step to copy the metadata.
mandel-macaque Feb 17, 2023
8bd978a
[CI] Fix the step to copy the metadata. (#13420)
mandel-macaque Feb 17, 2023
c2eec79
Merge branch 'main' into merge-main-net8
mandel-macaque Feb 17, 2023
fc0aa4e
Auto-format source code
Feb 17, 2023
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
4 changes: 2 additions & 2 deletions .github/workflows/dotnet-autoformat-pr-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
github.event.workflow_run.conclusion == 'success'
steps:
- name: 'Push autoformatted patch'
uses: rolfbjarne/autoformat-push@v0.1
uses: rolfbjarne/autoformat-push@v0.2
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}
commentContents: 'Thank you for your pull request. We are auto-formating your source code to follow our code guidelines.'
commentContents: 'Thank you for your pull request. We are auto-formating your source code to follow our code guidelines.'
16 changes: 8 additions & 8 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@
<MicrosoftWindowsSDKBuildToolsPackageVersion>10.0.22621.755</MicrosoftWindowsSDKBuildToolsPackageVersion>
<MicrosoftGraphicsWin2DPackageVersion>1.0.4</MicrosoftGraphicsWin2DPackageVersion>
<!-- Everything else -->
<MicrosoftAspNetCoreAuthorizationPackageVersion>7.0.2</MicrosoftAspNetCoreAuthorizationPackageVersion>
<MicrosoftAspNetCoreAuthenticationFacebookPackageVersion>7.0.2</MicrosoftAspNetCoreAuthenticationFacebookPackageVersion>
<MicrosoftAspNetCoreAuthenticationGooglePackageVersion>7.0.2</MicrosoftAspNetCoreAuthenticationGooglePackageVersion>
<MicrosoftAspNetCoreAuthenticationMicrosoftAccountPackageVersion>7.0.2</MicrosoftAspNetCoreAuthenticationMicrosoftAccountPackageVersion>
<MicrosoftAspNetCoreAuthorizationPackageVersion>7.0.3</MicrosoftAspNetCoreAuthorizationPackageVersion>
<MicrosoftAspNetCoreAuthenticationFacebookPackageVersion>7.0.3</MicrosoftAspNetCoreAuthenticationFacebookPackageVersion>
<MicrosoftAspNetCoreAuthenticationGooglePackageVersion>7.0.3</MicrosoftAspNetCoreAuthenticationGooglePackageVersion>
<MicrosoftAspNetCoreAuthenticationMicrosoftAccountPackageVersion>7.0.3</MicrosoftAspNetCoreAuthenticationMicrosoftAccountPackageVersion>
<MicrosoftAspNetCoreComponentsAnalyzersPackageVersion>7.0.1</MicrosoftAspNetCoreComponentsAnalyzersPackageVersion>
<MicrosoftAspNetCoreComponentsFormsPackageVersion>7.0.1</MicrosoftAspNetCoreComponentsFormsPackageVersion>
<MicrosoftAspNetCoreComponentsPackageVersion>7.0.1</MicrosoftAspNetCoreComponentsPackageVersion>
<MicrosoftAspNetCoreComponentsWebPackageVersion>7.0.2</MicrosoftAspNetCoreComponentsWebPackageVersion>
<MicrosoftAspNetCoreComponentsWebViewPackageVersion>7.0.2</MicrosoftAspNetCoreComponentsWebViewPackageVersion>
<MicrosoftAspNetCoreComponentsWebPackageVersion>7.0.3</MicrosoftAspNetCoreComponentsWebPackageVersion>
<MicrosoftAspNetCoreComponentsWebViewPackageVersion>7.0.3</MicrosoftAspNetCoreComponentsWebViewPackageVersion>
<MicrosoftAspNetCoreMetadataPackageVersion>7.0.1</MicrosoftAspNetCoreMetadataPackageVersion>
<MicrosoftJSInteropPackageVersion>7.0.2</MicrosoftJSInteropPackageVersion>
<MicrosoftJSInteropPackageVersion>7.0.3</MicrosoftJSInteropPackageVersion>
<!-- Other packages -->
<MicrosoftCodeAnalysisNetAnalyzersVersion>8.0.0-preview1.23067.2</MicrosoftCodeAnalysisNetAnalyzersVersion>
<MicrosoftCodeAnalysisPublicApiAnalyzersVersion>3.3.3</MicrosoftCodeAnalysisPublicApiAnalyzersVersion>
Expand All @@ -51,7 +51,7 @@
<SystemIOUnmanagedMemoryStreamPackageVersion>4.3.0</SystemIOUnmanagedMemoryStreamPackageVersion>
<SystemObjectModelPackageVersion>4.3.0</SystemObjectModelPackageVersion>
<SystemRuntimeCompilerServicesUnsafePackageVersion>6.0.0</SystemRuntimeCompilerServicesUnsafePackageVersion>
<_MicrosoftWebWebView2Version>1.0.1518.46</_MicrosoftWebWebView2Version>
<_MicrosoftWebWebView2Version>1.0.1587.40</_MicrosoftWebWebView2Version>
<!-- GLIDE - the android maven artifact in /src/Core/AndroidNative/maui/build.gradle -->
<!-- must be kept in sync with the binding library version to it here: -->
<_XamarinAndroidGlideVersion>4.13.2.2</_XamarinAndroidGlideVersion>
Expand Down
25 changes: 17 additions & 8 deletions eng/pipelines/common/pack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,48 +48,57 @@ steps:
- pwsh: ./build.ps1 --target=dotnet --configuration="Release" --verbosity=diagnostic --nugetsource="${{ parameters.nugetFolder }}"
displayName: 'Install .NET'
retryCountOnTaskFailure: 3
workingDirectory: ${{ parameters.checkoutDirectory }}
env:
DOTNET_TOKEN: $(dotnetbuilds-internal-container-read-token)
PRIVATE_BUILD: $(PrivateBuild)

- pwsh: ./build.ps1 --target=dotnet-pack --configuration="Release" --verbosity=diagnostic --nugetsource="${{ parameters.nugetFolder }}"
displayName: 'Pack .NET Maui'
name: PackMaui
workingDirectory: ${{ parameters.checkoutDirectory }}
env:
DOTNET_TOKEN: $(dotnetbuilds-internal-container-read-token)
PRIVATE_BUILD: $(PrivateBuild)

- ${{ if eq(parameters.platform, 'Windows') }}:
- pwsh: ./build.ps1 --target=dotnet-diff --configuration="Release" --verbosity=diagnostic
displayName: 'Diff .NET Maui artifacts with NuGet'
workingDirectory: ${{ parameters.checkoutDirectory }}

# artifacts
- task: CopyFiles@2
condition: always()
displayName: 'Copy files to staging'
inputs:
Contents: |
artifacts/**/*.*nupkg
artifacts/**/*.zip
artifacts/vs-workload.props
eng/automation/SignList.xml
!artifacts/docs-packs/**
${{ parameters.checkoutDirectory }}/artifacts/**/*.*nupkg
${{ parameters.checkoutDirectory }}/artifacts/**/*.zip
${{ parameters.checkoutDirectory }}/artifacts/vs-workload.props
${{ parameters.checkoutDirectory }}/eng/automation/SignList.xml
!${{ parameters.checkoutDirectory}}/artifacts/docs-packs/**
TargetFolder: $(build.artifactstagingdirectory)
flattenFolders: true

- task: CopyFiles@2
condition: always()
displayName: 'Copy metadata to staging'
inputs:
SourceFolder: artifacts
SourceFolder: ${{ parameters.checkoutDirectory }}/artifacts
Contents: |
metadata/**
api-diff/**
TargetFolder: $(build.artifactstagingdirectory)

- task: CopyFiles@2
displayName: 'Copy Log Files'
condition: always()
inputs:
Contents: |
artifacts/logs/**
${{ parameters.checkoutDirectory }}/artifacts/logs/**
TargetFolder: $(build.artifactstagingdirectory)/logs
flattenFolders: true

- task: PublishBuildArtifacts@1
condition: always()
displayName: publish artifacts
Expand All @@ -101,6 +110,6 @@ steps:
condition: always()
displayName: publish docs artifacts
inputs:
PathToPublish: artifacts/docs-packs
PathToPublish: ${{ parameters.checkoutDirectory }}/artifacts/docs-packs
ArtifactName: xml-docs

10 changes: 5 additions & 5 deletions src/Controls/src/Core/BindableObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public BindableObject()

readonly Dictionary<BindableProperty, BindablePropertyContext> _properties = new Dictionary<BindableProperty, BindablePropertyContext>(4);
bool _applying;
object _inheritedContext;
WeakReference _inheritedContext;

/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='BindingContextProperty']/Docs/*" />
public static readonly BindableProperty BindingContextProperty =
Expand All @@ -41,7 +41,7 @@ public BindableObject()
/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='BindingContext']/Docs/*" />
public object BindingContext
{
get => _inheritedContext ?? GetValue(BindingContextProperty);
get => _inheritedContext?.Target ?? GetValue(BindingContextProperty);
set => SetValue(BindingContextProperty, value);
}

Expand Down Expand Up @@ -238,7 +238,7 @@ public static void SetInheritedBindingContext(BindableObject bindable, object va
if (bpContext != null && ((bpContext.Attributes & BindableContextAttributes.IsManuallySet) != 0))
return;

object oldContext = bindable._inheritedContext;
object oldContext = bindable._inheritedContext?.Target;

if (ReferenceEquals(oldContext, value))
return;
Expand All @@ -253,7 +253,7 @@ public static void SetInheritedBindingContext(BindableObject bindable, object va
}
else
{
bindable._inheritedContext = value;
bindable._inheritedContext = new WeakReference(value);
}

bindable.ApplyBindings(skipBindingContext: false, fromBindingContextChanged: true);
Expand Down Expand Up @@ -557,7 +557,7 @@ internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChan

static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
{
object context = bindable._inheritedContext;
object context = bindable._inheritedContext?.Target;
var oldBinding = oldBindingBase as Binding;
var newBinding = newBindingBase as Binding;

Expand Down
8 changes: 7 additions & 1 deletion src/Controls/src/Core/BindingExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ public void SubscribeTo(INotifyPropertyChanged source, PropertyChangedEventHandl
_listener.SetTarget(listener);
}

public void Unsubscribe()
public void Unsubscribe(bool finalizer = false)
{
INotifyPropertyChanged source;
if (_source.TryGetTarget(out source) && source != null)
Expand All @@ -644,6 +644,10 @@ public void Unsubscribe()
if (bo != null)
bo.BindingContextChanged -= _bchandler;

// If we are called from a finalizer, WeakReference<T>.SetTarget() can throw InvalidOperationException
if (finalizer)
return;

_source.SetTarget(null);
_listener.SetTarget(null);
}
Expand All @@ -668,6 +672,8 @@ class BindingExpressionPart
readonly PropertyChangedEventHandler _changeHandler;
WeakPropertyChangedProxy _listener;

~BindingExpressionPart() => _listener?.Unsubscribe(finalizer: true);

public BindingExpressionPart(BindingExpression expression, string content, bool isIndexer = false)
{
_expression = expression;
Expand Down
6 changes: 2 additions & 4 deletions src/Controls/src/Core/Brush.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ namespace Microsoft.Maui.Controls
[System.ComponentModel.TypeConverter(typeof(BrushTypeConverter))]
public abstract partial class Brush : Element
{
static ImmutableBrush defaultBrush;
/// <include file="../../docs/Microsoft.Maui.Controls/Brush.xml" path="//Member[@MemberName='Default']/Docs/*" />
public static Brush Default
{
get { return new SolidColorBrush(null); }
}
public static Brush Default => defaultBrush ??= new(null);

public static implicit operator Brush(Color color) => new SolidColorBrush(color);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
aView.Measure(widthMeasureSpec, heightMeasureSpec);
SetMeasuredDimension(aView.MeasuredWidth, aView.MeasuredHeight);
}
else
SetMeasuredDimension(0, 0);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ internal UIContainerCell(string cellId, View view, Shell shell, object context)

if (_renderer == null)
{
_renderer = (IPlatformViewHandler)view.ToHandler(shell.FindMauiContext());
_renderer = (IPlatformViewHandler)view.ToHandler(view.FindMauiContext() ?? shell.FindMauiContext());
}

ContentView.AddSubview(_renderer.PlatformView);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ protected override void ConnectHandler(RecyclerView platformView)
base.ConnectHandler(platformView);
(platformView as IMauiRecyclerView<TItemsView>)?.SetUpNewElement(VirtualView);
}

protected override void DisconnectHandler(RecyclerView platformView)
{
base.DisconnectHandler(platformView);
(platformView as IMauiRecyclerView<TItemsView>)?.TearDownOldElement(VirtualView);
}

protected override RecyclerView CreatePlatformView() =>
new MauiRecyclerView<TItemsView, ItemsViewAdapter<TItemsView, IItemsViewSource>, IItemsViewSource>(Context, GetItemsLayout, CreateAdapter);

Expand Down
14 changes: 11 additions & 3 deletions src/Controls/src/Core/Handlers/Shell/Windows/ShellView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,17 +155,25 @@ IEnumerable<object> IterateItems(List<List<Element>> groups)

foreach (var item in group)
{
bool foundExistingVM = false;

// Check to see if this element already has a VM counter part
foreach (var navItem in FlyoutItems)
{
if (navItem is NavigationViewItemViewModel viewModel && viewModel.Data == item)
{
foundExistingVM = true;
yield return viewModel;
}
}

yield return new NavigationViewItemViewModel()
if (!foundExistingVM)
{
Data = item
};
yield return new NavigationViewItemViewModel()
{
Data = item
};
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ public void ResetBusyCount()

void OnPageBusy(IView sender, bool enabled)
{
// Verify that the page making the request is part of this activity
if (!PageIsInThisContext(sender))
{
return;
}

_busyCount = Math.Max(0, enabled ? _busyCount + 1 : _busyCount - 1);

UpdateProgressBarVisibility(_busyCount > 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ override Microsoft.Maui.Controls.ImageButton.IsEnabledCore.get -> bool
override Microsoft.Maui.Controls.SearchBar.IsEnabledCore.get -> bool
~Microsoft.Maui.Controls.WebView.UserAgent.get -> string
~Microsoft.Maui.Controls.WebView.UserAgent.set -> void
~override Microsoft.Maui.Controls.Handlers.Items.ItemsViewHandler<TItemsView>.DisconnectHandler(AndroidX.RecyclerView.Widget.RecyclerView platformView) -> void
~override Microsoft.Maui.Controls.LayoutOptions.Equals(object obj) -> bool
~override Microsoft.Maui.Controls.Region.Equals(object obj) -> bool
~override Microsoft.Maui.Controls.Shapes.Matrix.Equals(object obj) -> bool
Expand Down
3 changes: 3 additions & 0 deletions src/Controls/src/Core/TypedBinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ class PropertyChangedProxy
public BindingExpression.WeakPropertyChangedProxy Listener { get; }
readonly BindingBase _binding;
PropertyChangedEventHandler handler;

~PropertyChangedProxy() => Listener?.Unsubscribe(finalizer: true);

public INotifyPropertyChanged Part
{
get
Expand Down
77 changes: 77 additions & 0 deletions src/Controls/tests/Core.UnitTests/BindingUnitTests.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Xunit;
Expand Down Expand Up @@ -1185,6 +1187,81 @@ public void ValueUpdatedWithSelfPathOnTwoWayBinding(bool isDefault)
AssertNoErrorsLogged();
}


[Theory, Category("[Binding] Complex paths")]
[InlineData(BindingMode.OneWay)]
[InlineData(BindingMode.OneWayToSource)]
[InlineData(BindingMode.TwoWay)]
public async Task WeakPropertyChangedProxyDoesNotLeak(BindingMode mode)
{
var proxies = new List<WeakReference>();
WeakReference weakViewModel = null, weakBindable = null;

int i = 0;
void create()
{
if (i++ < 1024)
{
create();
return;
}

var binding = new Binding("Model.Model[1]");
var bindable = new MockBindable();
weakBindable = new WeakReference(bindable);

var viewmodel = new ComplexMockViewModel
{
Model = new ComplexMockViewModel
{
Model = new ComplexMockViewModel()
}
};

weakViewModel = new WeakReference(viewmodel);

bindable.BindingContext = viewmodel;
bindable.SetBinding(MockBindable.TextProperty, binding);

// Access private members:
// WeakPropertyChangedProxy proxy = binding._expression._parts[i]._listener;
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
var expression = binding.GetType().GetField("_expression", flags).GetValue(binding);
Assert.NotNull(expression);
var parts = expression.GetType().GetField("_parts", flags).GetValue(expression) as IEnumerable;
Assert.NotNull(parts);
foreach (var part in parts)
{
var listener = part.GetType().GetField("_listener", flags).GetValue(part);
if (listener == null)
continue;
proxies.Add(new WeakReference(listener));
}
Assert.NotEmpty(proxies); // Should be at least 1
};
create();

await Task.Yield();
GC.Collect();
GC.WaitForPendingFinalizers();

if (mode == BindingMode.TwoWay || mode == BindingMode.OneWay)
Assert.False(weakViewModel.IsAlive, "ViewModel wasn't collected");

if (mode == BindingMode.TwoWay || mode == BindingMode.OneWayToSource)
Assert.False(weakBindable.IsAlive, "Bindable wasn't collected");

// WeakPropertyChangedProxy won't go away until the second GC, BindingExpressionPart unsubscribes in its finalizer
await Task.Yield();
GC.Collect();
GC.WaitForPendingFinalizers();

foreach (var proxy in proxies)
{
Assert.False(proxy.IsAlive, "WeakPropertyChangedProxy wasn't collected");
}
}

[Theory, Category("[Binding] Complex paths")]
[InlineData(BindingMode.OneWay)]
[InlineData(BindingMode.OneWayToSource)]
Expand Down
Loading