From d7fae9efc8b86af98357da1e22c5a5ff629ba89d Mon Sep 17 00:00:00 2001
From: Prathamesh Narkhede
<55591622+prathameshnarkhede@users.noreply.github.com>
Date: Mon, 19 Aug 2024 09:32:53 -0700
Subject: [PATCH 1/7] Switch cancelButton image to FontImageSource allowing for
more flexible and scalable icon usage (#593)
* Switch cancelButton image to FontImageSource allowing for more flexible and scalable icon usage with support for Dark/Light mode fixes.
* Update cancelButton icon color to #6E6E6E
Removed unused resources.
---
src/Toolkit/Toolkit.Maui/Assets/x-small.png | Bin 164 -> 0 bytes
src/Toolkit/Toolkit.Maui/Assets/x.png | Bin 390 -> 0 bytes
src/Toolkit/Toolkit.Maui/SearchView/SearchView.cs | 2 +-
3 files changed, 1 insertion(+), 1 deletion(-)
delete mode 100644 src/Toolkit/Toolkit.Maui/Assets/x-small.png
delete mode 100644 src/Toolkit/Toolkit.Maui/Assets/x.png
diff --git a/src/Toolkit/Toolkit.Maui/Assets/x-small.png b/src/Toolkit/Toolkit.Maui/Assets/x-small.png
deleted file mode 100644
index 3f9dc9b4964fcfea98f18949a30a9defb48d385a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 164
zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjY)RhkE)4%caKYZ?lYt_Uo-U3d
z9-VKeY~($lz{BD{v-{Ag12?;MGZr{cJoxWi_
E$w9#NA-DFmo6((qSJwVw3ku{^Qi%N<{M>tvg=Wzkg}aVSKqG*lA%<_#
zx=FuyHd}k9d)7;)=@(5Xk+(Dd>9)zjZ2t)laa;Wldi$qd;olsW9xwB3-8E0Emw%mt
z*Dv{a>f@h8vyVL?u`-VZSKhKvOI`Bn@eGlPvpSQ%^<0UO+3da~?eUCwB~$t1Ih`VE
zeUZYNKtYwD8y0DLK|d_gvL;vl{SdnY$WRqbe-gYz=~2r52FL9mb{8zmJ2CIMr|V-i
z+vIoaZH}Kz37ls0yrp-`Gev`#CA$765|#dLs?D&wBv-vUP5JH4k2!ilU9pwM6NBU;
zL*!3Bwpo75V_tjgRo7F6LJ^@VarHkRePz{pFZ-iHRrDv*R2A8;KfV^}e5{*Md&WQ-
d5(W$^f0>sw@y{3A@JR(E;_2$=vd$@?2>`pkqmTdq
diff --git a/src/Toolkit/Toolkit.Maui/SearchView/SearchView.cs b/src/Toolkit/Toolkit.Maui/SearchView/SearchView.cs
index 36fd3faae..4504ea1c3 100644
--- a/src/Toolkit/Toolkit.Maui/SearchView/SearchView.cs
+++ b/src/Toolkit/Toolkit.Maui/SearchView/SearchView.cs
@@ -71,7 +71,7 @@ public SearchView()
if (GetTemplateChild(nameof(PART_CancelButton)) is ImageButton cancelButton)
{
- cancelButton.Source = ImageSource.FromResource($"Esri.ArcGISRuntime.Toolkit.Maui.Assets.x{suffix}.png", Assembly.GetAssembly(typeof(SearchView)));
+ cancelButton.Source = new FontImageSource { Glyph = "\ue30a", FontFamily = "calcite-ui-icons-24", Color = Color.FromArgb("#6E6E6E") };
}
BindingContext = this;
From 48eb833212bf4222b13ce10bde743b371187743c Mon Sep 17 00:00:00 2001
From: Prathamesh Narkhede
Date: Wed, 18 Sep 2024 09:25:26 -0700
Subject: [PATCH 2/7] Add platform-specific min size for SymbolDisplay on
Android to fix issue with Pixel 4 rendering.
---
src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs b/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
index c0cb335fb..f181185fb 100644
--- a/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
+++ b/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
@@ -161,8 +161,12 @@ private async Task UpdateSwatchAsync()
image.MaximumWidthRequest = imageData.Width / scale;
image.MaximumHeightRequest = imageData.Height / scale;
image.Source = await imageData.ToImageSourceAsync();
- SourceUpdated?.Invoke(this, EventArgs.Empty);
+ SourceUpdated?.Invoke(this, EventArgs.Empty);
#pragma warning restore ESRI1800
+#if ANDROID
+ this.MinimumWidthRequest = imageData.Width / scale;
+ this.MinimumHeightRequest = imageData.Height / scale;
+#endif
}
catch
{
From 783ca292d65acb9e5e4b741411de7651674775c2 Mon Sep 17 00:00:00 2001
From: Prathamesh Narkhede
Date: Wed, 18 Sep 2024 12:10:16 -0700
Subject: [PATCH 3/7] Reverting changing height and width and removing Border
to resolve the issue
---
.../Toolkit.SampleApp.Maui/Samples/SymbolEditorSample.xaml | 6 +-----
src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs | 6 +-----
2 files changed, 2 insertions(+), 10 deletions(-)
diff --git a/src/Samples/Toolkit.SampleApp.Maui/Samples/SymbolEditorSample.xaml b/src/Samples/Toolkit.SampleApp.Maui/Samples/SymbolEditorSample.xaml
index 9338eec7c..c60e44fb0 100644
--- a/src/Samples/Toolkit.SampleApp.Maui/Samples/SymbolEditorSample.xaml
+++ b/src/Samples/Toolkit.SampleApp.Maui/Samples/SymbolEditorSample.xaml
@@ -22,11 +22,7 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs b/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
index f181185fb..3fc0e6e5f 100644
--- a/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
+++ b/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
@@ -16,7 +16,7 @@
using System;
using Esri.ArcGISRuntime.Symbology;
-using Esri.ArcGISRuntime.Toolkit.Internal;
+using Esri.ArcGISRuntime.Toolkit.Internal;
namespace Esri.ArcGISRuntime.Toolkit.Maui;
@@ -163,10 +163,6 @@ private async Task UpdateSwatchAsync()
image.Source = await imageData.ToImageSourceAsync();
SourceUpdated?.Invoke(this, EventArgs.Empty);
#pragma warning restore ESRI1800
-#if ANDROID
- this.MinimumWidthRequest = imageData.Width / scale;
- this.MinimumHeightRequest = imageData.Height / scale;
-#endif
}
catch
{
From 7c5a644b2736f4ef4e4e3087b7cfb60021cdc6f6 Mon Sep 17 00:00:00 2001
From: Prathamesh Narkhede
Date: Wed, 18 Sep 2024 12:12:15 -0700
Subject: [PATCH 4/7] Fixing unnecessary line endings
---
.../SymbolDisplay/SymbolDisplay.cs | 420 +++++++++---------
1 file changed, 210 insertions(+), 210 deletions(-)
diff --git a/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs b/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
index 3fc0e6e5f..b923b1f93 100644
--- a/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
+++ b/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
@@ -1,214 +1,214 @@
-// /*******************************************************************************
-// * Copyright 2012-2018 Esri
-// *
-// * Licensed under the Apache License, Version 2.0 (the "License");
-// * you may not use this file except in compliance with the License.
-// * You may obtain a copy of the License at
-// *
-// * http://www.apache.org/licenses/LICENSE-2.0
-// *
-// * Unless required by applicable law or agreed to in writing, software
-// * distributed under the License is distributed on an "AS IS" BASIS,
-// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// * See the License for the specific language governing permissions and
-// * limitations under the License.
-// ******************************************************************************/
-
+// /*******************************************************************************
+// * Copyright 2012-2018 Esri
+// *
+// * Licensed under the Apache License, Version 2.0 (the "License");
+// * you may not use this file except in compliance with the License.
+// * You may obtain a copy of the License at
+// *
+// * http://www.apache.org/licenses/LICENSE-2.0
+// *
+// * Unless required by applicable law or agreed to in writing, software
+// * distributed under the License is distributed on an "AS IS" BASIS,
+// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// * See the License for the specific language governing permissions and
+// * limitations under the License.
+// ******************************************************************************/
+
using System;
-using Esri.ArcGISRuntime.Symbology;
+using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.Toolkit.Internal;
-
-namespace Esri.ArcGISRuntime.Toolkit.Maui;
-
-///
-/// A control that renders a .
-///
-public partial class SymbolDisplay : TemplatedView
-{
- private WeakEventListener? _inpcListener;
- private WeakEventListener? _displayDensityChangedListener;
- private Task? _currentUpdateTask;
- private bool _isRefreshRequired;
- private static readonly ControlTemplate DefaultControlTemplate;
- private Image? image;
- private double _lastScaleFactor = double.NaN;
-
- static SymbolDisplay()
- {
- string template = @"";
- DefaultControlTemplate = new ControlTemplate()
- {
- LoadTemplate = () =>
- {
- return Microsoft.Maui.Controls.Xaml.Extensions.LoadFromXaml(new Image(), template);
- }
- };
- }
- ///
- /// Initializes a new instance of the class.
- ///
- public SymbolDisplay()
- {
- ControlTemplate = DefaultControlTemplate;
- this.PropertyChanged += SymbolDisplay_PropertyChanged;
- }
-
- private void SymbolDisplay_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
- {
- if (e.PropertyName == nameof(Window) && Window != null)
- {
- if (_lastScaleFactor != GetScaleFactor())
- {
- Refresh();
- }
-
- _displayDensityChangedListener?.Detach();
-
- _displayDensityChangedListener = new WeakEventListener(this, Window)
- {
- OnEventAction = static (instance, source, eventArgs) =>
- {
- if (instance._lastScaleFactor != instance.GetScaleFactor())
- {
- instance.Refresh();
- }
- },
- OnDetachAction = static (instance, source, weakEventListener) => source.DisplayDensityChanged -= weakEventListener.OnEvent,
- };
- Window.DisplayDensityChanged += _displayDensityChangedListener.OnEvent;
- }
- }
-
- ///
- /// Gets or sets the symbol to render.
- ///
- public Symbology.Symbol? Symbol
- {
- get => (Symbol?)GetValue(SymbolProperty);
- set => SetValue(SymbolProperty, value);
- }
-
- ///
- /// Identifies the bindable property.
- ///
- public static readonly BindableProperty SymbolProperty =
- BindableProperty.Create(nameof(Symbol), typeof(Symbol), typeof(SymbolDisplay), null, propertyChanged: OnSymbolPropertyChanged);
-
- private static void OnSymbolPropertyChanged(BindableObject sender, object? oldValue, object? newValue)
- {
- ((SymbolDisplay)sender).OnSymbolChanged(oldValue as Symbol, newValue as Symbol);
- }
-
- private void OnSymbolChanged(Symbology.Symbol? oldValue, Symbology.Symbol? newValue)
- {
- if (oldValue != null)
- {
- _inpcListener?.Detach();
- _inpcListener = null;
- }
-
- if (newValue != null)
- {
- _inpcListener = new WeakEventListener(this, newValue)
- {
- OnEventAction = static (instance, source, eventArgs) =>
- {
- instance.Refresh();
- },
- OnDetachAction = static (instance, source, weakEventListener) => source.PropertyChanged -= weakEventListener.OnEvent,
- };
- newValue.PropertyChanged += _inpcListener.OnEvent;
- }
-
- Refresh();
- }
-
- ///
- protected override void OnApplyTemplate()
- {
- base.OnApplyTemplate();
- image = GetTemplateChild("image") as Image;
- Refresh();
- }
-
- private async Task UpdateSwatchAsync()
- {
-
- if (image is null)
- {
- return;
- }
-
- if (Symbol == null)
- {
- image.Source = null;
- image.MaximumWidthRequest = 0;
- image.MaximumHeightRequest = 0;
- }
- else
- {
- try
- {
- var scale = GetScaleFactor();
- _lastScaleFactor = scale;
-
- if (double.IsNaN(scale))
- {
- return;
- }
-#pragma warning disable ESRI1800 // Add ConfigureAwait(false) - This is UI Dependent code and must return to UI Thread
- var imageData = await Symbol.CreateSwatchAsync(scale * 96);
- image.MaximumWidthRequest = imageData.Width / scale;
- image.MaximumHeightRequest = imageData.Height / scale;
- image.Source = await imageData.ToImageSourceAsync();
+
+namespace Esri.ArcGISRuntime.Toolkit.Maui;
+
+///
+/// A control that renders a .
+///
+public partial class SymbolDisplay : TemplatedView
+{
+ private WeakEventListener? _inpcListener;
+ private WeakEventListener? _displayDensityChangedListener;
+ private Task? _currentUpdateTask;
+ private bool _isRefreshRequired;
+ private static readonly ControlTemplate DefaultControlTemplate;
+ private Image? image;
+ private double _lastScaleFactor = double.NaN;
+
+ static SymbolDisplay()
+ {
+ string template = @"";
+ DefaultControlTemplate = new ControlTemplate()
+ {
+ LoadTemplate = () =>
+ {
+ return Microsoft.Maui.Controls.Xaml.Extensions.LoadFromXaml(new Image(), template);
+ }
+ };
+ }
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SymbolDisplay()
+ {
+ ControlTemplate = DefaultControlTemplate;
+ this.PropertyChanged += SymbolDisplay_PropertyChanged;
+ }
+
+ private void SymbolDisplay_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(Window) && Window != null)
+ {
+ if (_lastScaleFactor != GetScaleFactor())
+ {
+ Refresh();
+ }
+
+ _displayDensityChangedListener?.Detach();
+
+ _displayDensityChangedListener = new WeakEventListener(this, Window)
+ {
+ OnEventAction = static (instance, source, eventArgs) =>
+ {
+ if (instance._lastScaleFactor != instance.GetScaleFactor())
+ {
+ instance.Refresh();
+ }
+ },
+ OnDetachAction = static (instance, source, weakEventListener) => source.DisplayDensityChanged -= weakEventListener.OnEvent,
+ };
+ Window.DisplayDensityChanged += _displayDensityChangedListener.OnEvent;
+ }
+ }
+
+ ///
+ /// Gets or sets the symbol to render.
+ ///
+ public Symbology.Symbol? Symbol
+ {
+ get => (Symbol?)GetValue(SymbolProperty);
+ set => SetValue(SymbolProperty, value);
+ }
+
+ ///
+ /// Identifies the bindable property.
+ ///
+ public static readonly BindableProperty SymbolProperty =
+ BindableProperty.Create(nameof(Symbol), typeof(Symbol), typeof(SymbolDisplay), null, propertyChanged: OnSymbolPropertyChanged);
+
+ private static void OnSymbolPropertyChanged(BindableObject sender, object? oldValue, object? newValue)
+ {
+ ((SymbolDisplay)sender).OnSymbolChanged(oldValue as Symbol, newValue as Symbol);
+ }
+
+ private void OnSymbolChanged(Symbology.Symbol? oldValue, Symbology.Symbol? newValue)
+ {
+ if (oldValue != null)
+ {
+ _inpcListener?.Detach();
+ _inpcListener = null;
+ }
+
+ if (newValue != null)
+ {
+ _inpcListener = new WeakEventListener(this, newValue)
+ {
+ OnEventAction = static (instance, source, eventArgs) =>
+ {
+ instance.Refresh();
+ },
+ OnDetachAction = static (instance, source, weakEventListener) => source.PropertyChanged -= weakEventListener.OnEvent,
+ };
+ newValue.PropertyChanged += _inpcListener.OnEvent;
+ }
+
+ Refresh();
+ }
+
+ ///
+ protected override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+ image = GetTemplateChild("image") as Image;
+ Refresh();
+ }
+
+ private async Task UpdateSwatchAsync()
+ {
+
+ if (image is null)
+ {
+ return;
+ }
+
+ if (Symbol == null)
+ {
+ image.Source = null;
+ image.MaximumWidthRequest = 0;
+ image.MaximumHeightRequest = 0;
+ }
+ else
+ {
+ try
+ {
+ var scale = GetScaleFactor();
+ _lastScaleFactor = scale;
+
+ if (double.IsNaN(scale))
+ {
+ return;
+ }
+#pragma warning disable ESRI1800 // Add ConfigureAwait(false) - This is UI Dependent code and must return to UI Thread
+ var imageData = await Symbol.CreateSwatchAsync(scale * 96);
+ image.MaximumWidthRequest = imageData.Width / scale;
+ image.MaximumHeightRequest = imageData.Height / scale;
+ image.Source = await imageData.ToImageSourceAsync();
SourceUpdated?.Invoke(this, EventArgs.Empty);
-#pragma warning restore ESRI1800
- }
- catch
- {
- image.Source = null;
- image.MaximumWidthRequest = 0;
- image.MaximumHeightRequest = 0;
- }
- }
- }
-
- private double GetScaleFactor() => Window?.DisplayDensity ?? double.NaN;
-
- private async void Refresh()
- {
- try
- {
- if (_currentUpdateTask != null)
- {
- // Instead of refreshing immediately when a refresh is already in progress, avoid updating too frequently, but just flag it dirty
- // This avoid multiple refreshes where properties change very frequently, but just the latest state gets refreshed.
- _isRefreshRequired = true;
- return;
- }
-
-#pragma warning disable SA1500 // Braces for multi-line statements should not share line
-
- do
- {
- _isRefreshRequired = false;
- var task = _currentUpdateTask = UpdateSwatchAsync();
- await task;
- } while (_isRefreshRequired);
-
-#pragma warning restore SA1500 // Braces for multi-line statements should not share line
-
- _currentUpdateTask = null;
- }
- catch (Exception)
- {
- // Ignore
- }
- }
- // Even though this code doesn't apply to .NET standard build, Visual Studio sill warns about it.
- ///
- /// Triggered when the image source has updated
- ///
- [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
- public event System.EventHandler? SourceUpdated;
+#pragma warning restore ESRI1800
+ }
+ catch
+ {
+ image.Source = null;
+ image.MaximumWidthRequest = 0;
+ image.MaximumHeightRequest = 0;
+ }
+ }
+ }
+
+ private double GetScaleFactor() => Window?.DisplayDensity ?? double.NaN;
+
+ private async void Refresh()
+ {
+ try
+ {
+ if (_currentUpdateTask != null)
+ {
+ // Instead of refreshing immediately when a refresh is already in progress, avoid updating too frequently, but just flag it dirty
+ // This avoid multiple refreshes where properties change very frequently, but just the latest state gets refreshed.
+ _isRefreshRequired = true;
+ return;
+ }
+
+#pragma warning disable SA1500 // Braces for multi-line statements should not share line
+
+ do
+ {
+ _isRefreshRequired = false;
+ var task = _currentUpdateTask = UpdateSwatchAsync();
+ await task;
+ } while (_isRefreshRequired);
+
+#pragma warning restore SA1500 // Braces for multi-line statements should not share line
+
+ _currentUpdateTask = null;
+ }
+ catch (Exception)
+ {
+ // Ignore
+ }
+ }
+ // Even though this code doesn't apply to .NET standard build, Visual Studio sill warns about it.
+ ///
+ /// Triggered when the image source has updated
+ ///
+ [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
+ public event System.EventHandler? SourceUpdated;
}
\ No newline at end of file
From bc03bb4737f4bcb2aa1f08224bf01d290bbeedcf Mon Sep 17 00:00:00 2001
From: Prathamesh Narkhede
Date: Wed, 18 Sep 2024 12:13:09 -0700
Subject: [PATCH 5/7] .
---
.../SymbolDisplay/SymbolDisplay.cs | 422 +++++++++---------
1 file changed, 211 insertions(+), 211 deletions(-)
diff --git a/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs b/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
index b923b1f93..206f6bbcb 100644
--- a/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
+++ b/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
@@ -1,214 +1,214 @@
-// /*******************************************************************************
-// * Copyright 2012-2018 Esri
-// *
-// * Licensed under the Apache License, Version 2.0 (the "License");
-// * you may not use this file except in compliance with the License.
-// * You may obtain a copy of the License at
-// *
-// * http://www.apache.org/licenses/LICENSE-2.0
-// *
-// * Unless required by applicable law or agreed to in writing, software
-// * distributed under the License is distributed on an "AS IS" BASIS,
-// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// * See the License for the specific language governing permissions and
-// * limitations under the License.
-// ******************************************************************************/
-
+// /*******************************************************************************
+// * Copyright 2012-2018 Esri
+// *
+// * Licensed under the Apache License, Version 2.0 (the "License");
+// * you may not use this file except in compliance with the License.
+// * You may obtain a copy of the License at
+// *
+// * http://www.apache.org/licenses/LICENSE-2.0
+// *
+// * Unless required by applicable law or agreed to in writing, software
+// * distributed under the License is distributed on an "AS IS" BASIS,
+// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// * See the License for the specific language governing permissions and
+// * limitations under the License.
+// ******************************************************************************/
+
using System;
-using Esri.ArcGISRuntime.Symbology;
-using Esri.ArcGISRuntime.Toolkit.Internal;
-
-namespace Esri.ArcGISRuntime.Toolkit.Maui;
-
-///
-/// A control that renders a .
-///
-public partial class SymbolDisplay : TemplatedView
-{
- private WeakEventListener? _inpcListener;
- private WeakEventListener? _displayDensityChangedListener;
- private Task? _currentUpdateTask;
- private bool _isRefreshRequired;
- private static readonly ControlTemplate DefaultControlTemplate;
- private Image? image;
- private double _lastScaleFactor = double.NaN;
-
- static SymbolDisplay()
- {
- string template = @"";
- DefaultControlTemplate = new ControlTemplate()
- {
- LoadTemplate = () =>
- {
- return Microsoft.Maui.Controls.Xaml.Extensions.LoadFromXaml(new Image(), template);
- }
- };
- }
- ///
- /// Initializes a new instance of the class.
- ///
- public SymbolDisplay()
- {
- ControlTemplate = DefaultControlTemplate;
- this.PropertyChanged += SymbolDisplay_PropertyChanged;
- }
-
- private void SymbolDisplay_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
- {
- if (e.PropertyName == nameof(Window) && Window != null)
- {
- if (_lastScaleFactor != GetScaleFactor())
- {
- Refresh();
- }
-
- _displayDensityChangedListener?.Detach();
-
- _displayDensityChangedListener = new WeakEventListener(this, Window)
- {
- OnEventAction = static (instance, source, eventArgs) =>
- {
- if (instance._lastScaleFactor != instance.GetScaleFactor())
- {
- instance.Refresh();
- }
- },
- OnDetachAction = static (instance, source, weakEventListener) => source.DisplayDensityChanged -= weakEventListener.OnEvent,
- };
- Window.DisplayDensityChanged += _displayDensityChangedListener.OnEvent;
- }
- }
-
- ///
- /// Gets or sets the symbol to render.
- ///
- public Symbology.Symbol? Symbol
- {
- get => (Symbol?)GetValue(SymbolProperty);
- set => SetValue(SymbolProperty, value);
- }
-
- ///
- /// Identifies the bindable property.
- ///
- public static readonly BindableProperty SymbolProperty =
- BindableProperty.Create(nameof(Symbol), typeof(Symbol), typeof(SymbolDisplay), null, propertyChanged: OnSymbolPropertyChanged);
-
- private static void OnSymbolPropertyChanged(BindableObject sender, object? oldValue, object? newValue)
- {
- ((SymbolDisplay)sender).OnSymbolChanged(oldValue as Symbol, newValue as Symbol);
- }
-
- private void OnSymbolChanged(Symbology.Symbol? oldValue, Symbology.Symbol? newValue)
- {
- if (oldValue != null)
- {
- _inpcListener?.Detach();
- _inpcListener = null;
- }
-
- if (newValue != null)
- {
- _inpcListener = new WeakEventListener(this, newValue)
- {
- OnEventAction = static (instance, source, eventArgs) =>
- {
- instance.Refresh();
- },
- OnDetachAction = static (instance, source, weakEventListener) => source.PropertyChanged -= weakEventListener.OnEvent,
- };
- newValue.PropertyChanged += _inpcListener.OnEvent;
- }
-
- Refresh();
- }
-
- ///
- protected override void OnApplyTemplate()
- {
- base.OnApplyTemplate();
- image = GetTemplateChild("image") as Image;
- Refresh();
- }
-
- private async Task UpdateSwatchAsync()
- {
-
- if (image is null)
- {
- return;
- }
-
- if (Symbol == null)
- {
- image.Source = null;
- image.MaximumWidthRequest = 0;
- image.MaximumHeightRequest = 0;
- }
- else
- {
- try
- {
- var scale = GetScaleFactor();
- _lastScaleFactor = scale;
-
- if (double.IsNaN(scale))
- {
- return;
- }
-#pragma warning disable ESRI1800 // Add ConfigureAwait(false) - This is UI Dependent code and must return to UI Thread
- var imageData = await Symbol.CreateSwatchAsync(scale * 96);
- image.MaximumWidthRequest = imageData.Width / scale;
- image.MaximumHeightRequest = imageData.Height / scale;
- image.Source = await imageData.ToImageSourceAsync();
+using Esri.ArcGISRuntime.Symbology;
+using Esri.ArcGISRuntime.Toolkit.Internal;
+
+namespace Esri.ArcGISRuntime.Toolkit.Maui;
+
+///
+/// A control that renders a .
+///
+public partial class SymbolDisplay : TemplatedView
+{
+ private WeakEventListener? _inpcListener;
+ private WeakEventListener? _displayDensityChangedListener;
+ private Task? _currentUpdateTask;
+ private bool _isRefreshRequired;
+ private static readonly ControlTemplate DefaultControlTemplate;
+ private Image? image;
+ private double _lastScaleFactor = double.NaN;
+
+ static SymbolDisplay()
+ {
+ string template = @"";
+ DefaultControlTemplate = new ControlTemplate()
+ {
+ LoadTemplate = () =>
+ {
+ return Microsoft.Maui.Controls.Xaml.Extensions.LoadFromXaml(new Image(), template);
+ }
+ };
+ }
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SymbolDisplay()
+ {
+ ControlTemplate = DefaultControlTemplate;
+ this.PropertyChanged += SymbolDisplay_PropertyChanged;
+ }
+
+ private void SymbolDisplay_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(Window) && Window != null)
+ {
+ if (_lastScaleFactor != GetScaleFactor())
+ {
+ Refresh();
+ }
+
+ _displayDensityChangedListener?.Detach();
+
+ _displayDensityChangedListener = new WeakEventListener(this, Window)
+ {
+ OnEventAction = static (instance, source, eventArgs) =>
+ {
+ if (instance._lastScaleFactor != instance.GetScaleFactor())
+ {
+ instance.Refresh();
+ }
+ },
+ OnDetachAction = static (instance, source, weakEventListener) => source.DisplayDensityChanged -= weakEventListener.OnEvent,
+ };
+ Window.DisplayDensityChanged += _displayDensityChangedListener.OnEvent;
+ }
+ }
+
+ ///
+ /// Gets or sets the symbol to render.
+ ///
+ public Symbology.Symbol? Symbol
+ {
+ get => (Symbol?)GetValue(SymbolProperty);
+ set => SetValue(SymbolProperty, value);
+ }
+
+ ///
+ /// Identifies the bindable property.
+ ///
+ public static readonly BindableProperty SymbolProperty =
+ BindableProperty.Create(nameof(Symbol), typeof(Symbol), typeof(SymbolDisplay), null, propertyChanged: OnSymbolPropertyChanged);
+
+ private static void OnSymbolPropertyChanged(BindableObject sender, object? oldValue, object? newValue)
+ {
+ ((SymbolDisplay)sender).OnSymbolChanged(oldValue as Symbol, newValue as Symbol);
+ }
+
+ private void OnSymbolChanged(Symbology.Symbol? oldValue, Symbology.Symbol? newValue)
+ {
+ if (oldValue != null)
+ {
+ _inpcListener?.Detach();
+ _inpcListener = null;
+ }
+
+ if (newValue != null)
+ {
+ _inpcListener = new WeakEventListener(this, newValue)
+ {
+ OnEventAction = static (instance, source, eventArgs) =>
+ {
+ instance.Refresh();
+ },
+ OnDetachAction = static (instance, source, weakEventListener) => source.PropertyChanged -= weakEventListener.OnEvent,
+ };
+ newValue.PropertyChanged += _inpcListener.OnEvent;
+ }
+
+ Refresh();
+ }
+
+ ///
+ protected override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+ image = GetTemplateChild("image") as Image;
+ Refresh();
+ }
+
+ private async Task UpdateSwatchAsync()
+ {
+
+ if (image is null)
+ {
+ return;
+ }
+
+ if (Symbol == null)
+ {
+ image.Source = null;
+ image.MaximumWidthRequest = 0;
+ image.MaximumHeightRequest = 0;
+ }
+ else
+ {
+ try
+ {
+ var scale = GetScaleFactor();
+ _lastScaleFactor = scale;
+
+ if (double.IsNaN(scale))
+ {
+ return;
+ }
+#pragma warning disable ESRI1800 // Add ConfigureAwait(false) - This is UI Dependent code and must return to UI Thread
+ var imageData = await Symbol.CreateSwatchAsync(scale * 96);
+ image.MaximumWidthRequest = imageData.Width / scale;
+ image.MaximumHeightRequest = imageData.Height / scale;
+ image.Source = await imageData.ToImageSourceAsync();
SourceUpdated?.Invoke(this, EventArgs.Empty);
-#pragma warning restore ESRI1800
- }
- catch
- {
- image.Source = null;
- image.MaximumWidthRequest = 0;
- image.MaximumHeightRequest = 0;
- }
- }
- }
-
- private double GetScaleFactor() => Window?.DisplayDensity ?? double.NaN;
-
- private async void Refresh()
- {
- try
- {
- if (_currentUpdateTask != null)
- {
- // Instead of refreshing immediately when a refresh is already in progress, avoid updating too frequently, but just flag it dirty
- // This avoid multiple refreshes where properties change very frequently, but just the latest state gets refreshed.
- _isRefreshRequired = true;
- return;
- }
-
-#pragma warning disable SA1500 // Braces for multi-line statements should not share line
-
- do
- {
- _isRefreshRequired = false;
- var task = _currentUpdateTask = UpdateSwatchAsync();
- await task;
- } while (_isRefreshRequired);
-
-#pragma warning restore SA1500 // Braces for multi-line statements should not share line
-
- _currentUpdateTask = null;
- }
- catch (Exception)
- {
- // Ignore
- }
- }
- // Even though this code doesn't apply to .NET standard build, Visual Studio sill warns about it.
- ///
- /// Triggered when the image source has updated
- ///
- [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
- public event System.EventHandler? SourceUpdated;
+#pragma warning restore ESRI1800
+ }
+ catch
+ {
+ image.Source = null;
+ image.MaximumWidthRequest = 0;
+ image.MaximumHeightRequest = 0;
+ }
+ }
+ }
+
+ private double GetScaleFactor() => Window?.DisplayDensity ?? double.NaN;
+
+ private async void Refresh()
+ {
+ try
+ {
+ if (_currentUpdateTask != null)
+ {
+ // Instead of refreshing immediately when a refresh is already in progress, avoid updating too frequently, but just flag it dirty
+ // This avoid multiple refreshes where properties change very frequently, but just the latest state gets refreshed.
+ _isRefreshRequired = true;
+ return;
+ }
+
+#pragma warning disable SA1500 // Braces for multi-line statements should not share line
+
+ do
+ {
+ _isRefreshRequired = false;
+ var task = _currentUpdateTask = UpdateSwatchAsync();
+ await task;
+ } while (_isRefreshRequired);
+
+#pragma warning restore SA1500 // Braces for multi-line statements should not share line
+
+ _currentUpdateTask = null;
+ }
+ catch (Exception)
+ {
+ // Ignore
+ }
+ }
+ // Even though this code doesn't apply to .NET standard build, Visual Studio sill warns about it.
+ ///
+ /// Triggered when the image source has updated
+ ///
+ [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
+ public event System.EventHandler? SourceUpdated;
}
\ No newline at end of file
From e082673cc5ce0f9cba1c7480016221b6fd166a99 Mon Sep 17 00:00:00 2001
From: Prathamesh Narkhede
Date: Wed, 18 Sep 2024 12:13:48 -0700
Subject: [PATCH 6/7] .
---
src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs b/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
index 206f6bbcb..c0cb335fb 100644
--- a/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
+++ b/src/Toolkit/Toolkit.Maui/SymbolDisplay/SymbolDisplay.cs
@@ -161,7 +161,7 @@ private async Task UpdateSwatchAsync()
image.MaximumWidthRequest = imageData.Width / scale;
image.MaximumHeightRequest = imageData.Height / scale;
image.Source = await imageData.ToImageSourceAsync();
- SourceUpdated?.Invoke(this, EventArgs.Empty);
+ SourceUpdated?.Invoke(this, EventArgs.Empty);
#pragma warning restore ESRI1800
}
catch
From 268e396df336fc64c41cb2c2644ed4c0697853a6 Mon Sep 17 00:00:00 2001
From: Prathamesh Narkhede
Date: Thu, 19 Sep 2024 16:50:03 -0700
Subject: [PATCH 7/7] Fixing SymbolDisplay on Android Pixel 4 device by
removing Border element
---
.../Samples/SymbolDisplaySample.xaml.cs | 15 +++------------
1 file changed, 3 insertions(+), 12 deletions(-)
diff --git a/src/Samples/Toolkit.SampleApp.Maui/Samples/SymbolDisplaySample.xaml.cs b/src/Samples/Toolkit.SampleApp.Maui/Samples/SymbolDisplaySample.xaml.cs
index f988eab08..d0bd7c66e 100644
--- a/src/Samples/Toolkit.SampleApp.Maui/Samples/SymbolDisplaySample.xaml.cs
+++ b/src/Samples/Toolkit.SampleApp.Maui/Samples/SymbolDisplaySample.xaml.cs
@@ -38,23 +38,14 @@ private void AddSymbol(Symbol symbol)
{
int columnCount = LayoutRoot.ColumnDefinitions.Count;
var sd = new SymbolDisplay() { Symbol = symbol };
- Border border = new Border()
- {
- HorizontalOptions = LayoutOptions.Center,
- VerticalOptions = LayoutOptions.Center,
- Padding = 0,
- StrokeThickness = 1,
- };
- border.SetAppThemeColor(Microsoft.Maui.Controls.Border.StrokeProperty, Colors.Black, Colors.White);
- border.Content = sd;
int count = LayoutRoot.Children.Count;
var row = count / columnCount;
var column = count % columnCount;
if (column == 0)
LayoutRoot.RowDefinitions.Add(new RowDefinition());
- Grid.SetRow(border, row);
- Grid.SetColumn(border, column);
- LayoutRoot.Children.Add(border);
+ Grid.SetRow(sd, row);
+ Grid.SetColumn(sd, column);
+ LayoutRoot.Children.Add(sd);
}
}
}
\ No newline at end of file