diff --git a/src/Controls/src/Core/Button/Button.cs b/src/Controls/src/Core/Button/Button.cs
index 3ccba944ec54..2c9452712458 100644
--- a/src/Controls/src/Core/Button/Button.cs
+++ b/src/Controls/src/Core/Button/Button.cs
@@ -616,5 +616,7 @@ private protected override string GetDebuggerDisplay()
var commandText = DebuggerDisplayHelpers.GetDebugText(nameof(Command), Command, false);
return $"{base.GetDebuggerDisplay()}, {textString}, {commandText}";
}
+
+ WeakCommandSubscription ICommandElement.CleanupTracker { get; set; }
}
}
diff --git a/src/Controls/src/Core/Cells/TextCell.cs b/src/Controls/src/Core/Cells/TextCell.cs
index 544f6ba58615..283ccedc653b 100644
--- a/src/Controls/src/Core/Cells/TextCell.cs
+++ b/src/Controls/src/Core/Cells/TextCell.cs
@@ -1,42 +1,27 @@
#nullable disable
using System;
using System.Windows.Input;
+using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Graphics;
namespace Microsoft.Maui.Controls
{
///
- public class TextCell : Cell
+ public class TextCell : Cell, ICommandElement
{
/// Bindable property for .
- public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(TextCell), default(ICommand),
- propertyChanging: (bindable, oldvalue, newvalue) =>
- {
- var textCell = (TextCell)bindable;
- var oldcommand = (ICommand)oldvalue;
- if (oldcommand != null)
- oldcommand.CanExecuteChanged -= textCell.OnCommandCanExecuteChanged;
- }, propertyChanged: (bindable, oldvalue, newvalue) =>
- {
- var textCell = (TextCell)bindable;
- var newcommand = (ICommand)newvalue;
- if (newcommand != null)
- {
- textCell.IsEnabled = newcommand.CanExecute(textCell.CommandParameter);
- newcommand.CanExecuteChanged += textCell.OnCommandCanExecuteChanged;
- }
- });
+ public static readonly BindableProperty CommandProperty =
+ BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(TextCell),
+ propertyChanging: CommandElement.OnCommandChanging,
+ propertyChanged: CommandElement.OnCommandChanged);
/// Bindable property for .
- public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create(nameof(CommandParameter), typeof(object), typeof(TextCell), default(object),
- propertyChanged: (bindable, oldvalue, newvalue) =>
- {
- var textCell = (TextCell)bindable;
- if (textCell.Command != null)
- {
- textCell.IsEnabled = textCell.Command.CanExecute(newvalue);
- }
- });
+ public static readonly BindableProperty CommandParameterProperty =
+ BindableProperty.Create(nameof(CommandParameter),
+ typeof(object),
+ typeof(TextCell),
+ null,
+ propertyChanged: CommandElement.OnCommandParameterChanged);
/// Bindable property for .
public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(TextCell), default(string));
@@ -104,9 +89,14 @@ protected internal override void OnTapped()
Command?.Execute(CommandParameter);
}
- void OnCommandCanExecuteChanged(object sender, EventArgs eventArgs)
+ void ICommandElement.CanExecuteChanged(object sender, EventArgs eventArgs)
{
+ if (Command is null)
+ return;
+
IsEnabled = Command.CanExecute(CommandParameter);
}
+
+ WeakCommandSubscription ICommandElement.CleanupTracker { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Controls/src/Core/CommandElement.cs b/src/Controls/src/Core/CommandElement.cs
index 7c84c4f3f1a6..6a4a70de5519 100644
--- a/src/Controls/src/Core/CommandElement.cs
+++ b/src/Controls/src/Core/CommandElement.cs
@@ -10,15 +10,24 @@ static class CommandElement
public static void OnCommandChanging(BindableObject bo, object o, object n)
{
var commandElement = (ICommandElement)bo;
- if (o is ICommand oldCommand)
- oldCommand.CanExecuteChanged -= commandElement.CanExecuteChanged;
+ commandElement.CleanupTracker?.Dispose();
+ commandElement.CleanupTracker = null;
}
public static void OnCommandChanged(BindableObject bo, object o, object n)
{
var commandElement = (ICommandElement)bo;
- if (n is ICommand newCommand)
- newCommand.CanExecuteChanged += commandElement.CanExecuteChanged;
+
+ if (n is null)
+ {
+ commandElement.CleanupTracker?.Dispose();
+ commandElement.CleanupTracker = null;
+ }
+ else
+ {
+ commandElement.CleanupTracker = new WeakCommandSubscription(bo, (ICommand)n, commandElement.CanExecuteChanged);
+ }
+
commandElement.CanExecuteChanged(bo, EventArgs.Empty);
}
@@ -36,4 +45,4 @@ public static bool GetCanExecute(ICommandElement commandElement)
return commandElement.Command.CanExecute(commandElement.CommandParameter);
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Controls/src/Core/DepdendentHandle.cs b/src/Controls/src/Core/DepdendentHandle.cs
new file mode 100644
index 000000000000..c625dde69c00
--- /dev/null
+++ b/src/Controls/src/Core/DepdendentHandle.cs
@@ -0,0 +1,96 @@
+#nullable enable
+
+#if NETSTANDARD2_0 || NETSTANDARD2_1
+using System;
+using System.Runtime;
+using System.Runtime.CompilerServices;
+using System.Windows.Input;
+
+namespace System.Runtime;
+
+///
+/// A wrapper around ConditionalWeakTable that replicates DependentHandle behavior.
+/// Creates a dependency between a primary object and a dependent object where
+/// the dependent object becomes eligible for collection when the primary is collected.
+///
+internal class DependentHandle : IDisposable
+{
+ private readonly ConditionalWeakTable