This commit is contained in:
Gerald Versluis 2020-01-06 11:43:40 +01:00
Родитель dbb259ff24 1ae8fb1cd5
Коммит 1b9c22b4b9
53 изменённых файлов: 1831 добавлений и 882 удалений

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

@ -390,14 +390,22 @@ namespace Xamarin.Forms.Build.Tasks
public static TypeReference ResolveGenericParameters(this TypeReference self, TypeReference declaringTypeReference) public static TypeReference ResolveGenericParameters(this TypeReference self, TypeReference declaringTypeReference)
{ {
var genericdeclType = declaringTypeReference as GenericInstanceType; var genericdeclType = declaringTypeReference as GenericInstanceType;
if (genericdeclType == null) var genericParameterSelf = self as GenericParameter;
var genericself = self as GenericInstanceType;
if (genericdeclType == null && genericParameterSelf == null && genericself == null)
return self; return self;
var genericParameterSelf = self as GenericParameter; if (genericdeclType == null && genericParameterSelf!=null)
{
var typeDef = declaringTypeReference.Resolve();
if (typeDef.BaseType == null || typeDef.BaseType.FullName == "System.Object")
return self;
return self.ResolveGenericParameters(typeDef.BaseType.ResolveGenericParameters(declaringTypeReference));
}
if (genericParameterSelf != null) if (genericParameterSelf != null)
return genericdeclType.GenericArguments[genericParameterSelf.Position]; return genericdeclType.GenericArguments[genericParameterSelf.Position];
var genericself = self as GenericInstanceType;
if (genericself != null) if (genericself != null)
return genericself.ResolveGenericParameters(declaringTypeReference); return genericself.ResolveGenericParameters(declaringTypeReference);

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

@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using System.Linq;
#if UITEST
using Xamarin.UITest;
using NUnit.Framework;
using Xamarin.Forms.Core.UITests;
#endif
namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 8262, "[Android] ImageRenderer still being accessed after control destroyed",
PlatformAffected.Android)]
#if UITEST
[NUnit.Framework.Category(UITestCategories.LifeCycle)]
[NUnit.Framework.Category(UITestCategories.CollectionView)]
#endif
public class Issue8262 : TestContentPage
{
public View WithBounds(View v, double x, double y, double w, double h)
{
AbsoluteLayout.SetLayoutBounds(v, new Rectangle(x, y, w, h));
return v;
}
protected override void Init()
{
IEnumerable<View> Select((string groupHeader, IEnumerable<int> items) t)
{
yield return new AbsoluteLayout
{
Children = {
WithBounds(new Label {
Text = t.groupHeader, HorizontalTextAlignment = TextAlignment.Center,
TextColor = Color.FromUint(0xff5a5a5a), FontSize = 10
}, 0, 21.1, 310, AbsoluteLayout.AutoSize) },
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.Start,
HeightRequest = 46
};
foreach (var item in t.items)
{
yield return new AbsoluteLayout
{
Children = {
WithBounds(new Image { Source = ImageSource.FromResource("Xamarin.Forms.Controls.GalleryPages.crimson.jpg", System.Reflection.Assembly.GetCallingAssembly()) }, 23.6, 14.5, 14.9, 20.7),
WithBounds(new Label { Text = item.ToString(), TextColor = Color.FromUint(0xff5a5a5a), FontSize = 10 }, 58, 18.2, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize)
},
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.Start,
HeightRequest = 49.7
};
}
}
Content = new AbsoluteLayout
{
Children = {
new CollectionView {
ItemsSource =
new (string, Func<int, bool>)[] {
("odd", i => i % 2 == 1),
("even", i => i % 2 == 0),
("triple", i => i % 3 == 0),
("fives", i => i % 5 == 0) }
.Select(t => (t.Item1, Enumerable.Range(1, 100).Where(t.Item2)))
.SelectMany(Select),
ItemTemplate = new DataTemplate(() => {
var template = new ContentView();
template.SetBinding(ContentView.ContentProperty, ".");
return template;
}),
ItemsLayout = LinearItemsLayout.Vertical,
ItemSizingStrategy = ItemSizingStrategy.MeasureFirstItem,
AutomationId = "ScrollMe"
}
}
};
}
#if UITEST
[Test]
public void ScrollingQuicklyOnCollectionViewDoesntCrashOnDestroyedImage()
{
RunningApp.WaitForElement("ScrollMe");
RunningApp.ScrollDown("ScrollMe", ScrollStrategy.Gesture, swipeSpeed: 20000);
RunningApp.ScrollUp("ScrollMe", ScrollStrategy.Gesture, swipeSpeed: 20000);
RunningApp.ScrollDown("ScrollMe", ScrollStrategy.Gesture, swipeSpeed: 20000);
RunningApp.ScrollUp("ScrollMe", ScrollStrategy.Gesture, swipeSpeed: 20000);
RunningApp.ScrollDown("ScrollMe", ScrollStrategy.Gesture, swipeSpeed: 20000);
RunningApp.WaitForElement("ScrollMe");
}
#endif
}
}

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

@ -0,0 +1,110 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
#if UITEST
using NUnit.Framework;
using Xamarin.Forms.Core.UITests;
#endif
namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 8461, "[Bug] [iOS] [Shell] \"Nav Stack consistency error\"",
PlatformAffected.iOS)]
#if UITEST
[NUnit.Framework.Category(UITestCategories.Shell)]
[NUnit.Framework.Category(UITestCategories.Navigation)]
#endif
public class Issue8461 : TestShell
{
const string ButtonId = "PageButtonId";
const string LayoutId = "LayoutId";
protected override void Init()
{
var page1 = CreateContentPage("page 1");
var page2 = new ContentPage() { Title = "page 2" };
var pushPageBtn = new Button();
pushPageBtn.Text = "Push Page";
pushPageBtn.AutomationId = ButtonId;
pushPageBtn.Clicked += (sender, args) =>
{
Navigation.PushAsync(page2);
};
page1.Content = new StackLayout()
{
Children =
{
pushPageBtn
}
};
var instructions = new StackLayout()
{
Children =
{
new Label()
{
Text = "1. Swipe left to dismiss this page, but cancel the gesture before it completes"
},
new Label()
{
Text = "2. Swipe left to dismiss this page again, crashes immediately"
}
}
};
Grid.SetColumn(instructions, 1);
page2.Content = new Grid()
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
ColumnDefinitions = new ColumnDefinitionCollection()
{
new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) },
new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) },
},
Children =
{
// Use this BoxView to achor our swipe to left of the screen
new BoxView()
{
AutomationId = LayoutId,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
BackgroundColor = Color.Red
},
instructions
}
};
}
#if UITEST && __IOS__
[Test]
public void ShellSwipeToDismiss()
{
var pushButton = RunningApp.WaitForElement(ButtonId);
Assert.AreEqual(1, pushButton.Length);
RunningApp.Tap(ButtonId);
var page2Layout = RunningApp.WaitForElement(LayoutId);
Assert.AreEqual(1, page2Layout.Length);
// Swipe in from left across 1/2 of screen width
RunningApp.SwipeLeftToRight(LayoutId, 0.99, 500, false);
// Swipe in from left across full screen width
RunningApp.SwipeLeftToRight(0.99, 500);
pushButton = RunningApp.WaitForElement(ButtonId);
Assert.AreEqual(1, pushButton.Length);
}
#endif
}
}

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

@ -0,0 +1,54 @@
using System.ComponentModel;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 8644, "WPF Entry crashes when IsPassword=true", PlatformAffected.WPF)]
public class Issue8644 : TestContentPage
{
public class BinCon : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
string _title;
public string Title
{
get => _title;
set
{
_title = value?.Length > 4 ? value.Substring(0, 4) : value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
}
}
}
protected override void Init()
{
var bc = new BinCon();
var e1 = new Entry
{
BindingContext = bc,
Margin = new Thickness(50),
HorizontalOptions = LayoutOptions.FillAndExpand,
IsPassword = true,
};
e1.SetBinding(Entry.TextProperty, nameof(BinCon.Title));
// Label just to show current Entry text, not needed for test
var lbl = new Label { BindingContext = bc };
lbl.SetBinding(Label.TextProperty, nameof(BinCon.Title));
var stack = new StackLayout
{
Children = {
new Label { Text = "Type more than 4 symbols" },
e1,
lbl,
}
};
Content = stack;
}
}
}

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

@ -0,0 +1,166 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System;
#if UITEST
using Xamarin.Forms.Core.UITests;
using Xamarin.UITest;
using NUnit.Framework;
#endif
namespace Xamarin.Forms.Controls.Issues
{
#if UITEST
[NUnit.Framework.Category(UITestCategories.Shell)]
#endif
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 8741, "[Bug] [Shell] [Android] ToolbarItem Enabled/Disabled behavior does not work for Shell apps", PlatformAffected.Android)]
public class Issue8741 : TestShell
{
protected override void Init()
{
var page = CreateContentPage();
var toolbarItem = new ToolbarItem
{
Text = "Add",
AutomationId = "Add"
};
toolbarItem.SetBinding(MenuItem.CommandProperty, "ToolbarTappedCommand");
page.ToolbarItems.Add(toolbarItem);
var button = new Button
{
Text = "Toggle Enabled/Disabled",
AutomationId = "ToggleEnabled"
};
button.SetBinding(Button.CommandProperty, "ChangeToggleCommand");
var label = new Label();
label.SetBinding(Label.TextProperty, "EnabledText");
var clickCount = new Label();
clickCount.AutomationId = "ClickCount";
clickCount.SetBinding(Label.TextProperty, "ClickCount");
page.Content =
new StackLayout
{
Children =
{
label,
clickCount,
button
}
};
BindingContext = new ViewModelIssue8741();
}
#if UITEST
[Test]
public void Issue8741Test()
{
RunningApp.WaitForElement("Add");
RunningApp.Tap("Add");
#if __ANDROID__
var toolbarItemColorValue = GetToolbarItemColorValue();
int disabledAlpha = GetAlphaValue(toolbarItemColorValue);
#endif
Assert.AreEqual("0", RunningApp.WaitForElement("ClickCount")[0].ReadText());
RunningApp.Tap("ToggleEnabled");
RunningApp.Tap("Add");
#if __ANDROID__
toolbarItemColorValue = GetToolbarItemColorValue();
int enabledAlpha = GetAlphaValue(toolbarItemColorValue);
Assert.Less(disabledAlpha, enabledAlpha);
#endif
Assert.AreEqual("1", RunningApp.WaitForElement("ClickCount")[0].ReadText());
RunningApp.Tap("ToggleEnabled");
RunningApp.Tap("Add");
Assert.AreEqual("1", RunningApp.WaitForElement("ClickCount")[0].ReadText());
}
#if __ANDROID__
private object GetToolbarItemColorValue()
{
return RunningApp.Query(x => x.Text("Add").Invoke("getCurrentTextColor"))[0];
}
private int GetAlphaValue(object toolbarItemColorValue)
{
int color = Convert.ToInt32(toolbarItemColorValue);
int a = (color >> 24) & 0xff;
return a;
}
#endif
#endif
[Preserve(AllMembers = true)]
public class ViewModelIssue8741 : INotifyPropertyChanged
{
bool _canAddNewItem;
int _clickCount;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public bool Enabled
{
get => _canAddNewItem;
set
{
_canAddNewItem = value;
OnPropertyChanged(nameof(Enabled));
ToolbarTappedCommand.ChangeCanExecute();
}
}
public int ClickCount
{
get
{
return _clickCount;
}
set
{
_clickCount = value;
OnPropertyChanged(nameof(ClickCount));
}
}
public string EnabledText { get; set; }
public Command ChangeToggleCommand { get; set; }
public Command ToolbarTappedCommand { get; set; }
public ViewModelIssue8741()
{
ChangeToggleCommand = new Command(ChangeToggle);
ToolbarTappedCommand = new Command(ToolbarTapped, () => Enabled);
EnabledText = Enabled ? "Enabled" : "Disabled";
}
void ToolbarTapped()
{
ClickCount++;
}
void ChangeToggle()
{
Enabled = !Enabled;
EnabledText = Enabled ? "Enabled" : "Disabled";
OnPropertyChanged(nameof(EnabledText));
}
}
}
}

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

@ -0,0 +1,108 @@
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
#if UITEST
using Xamarin.Forms.Core.UITests;
using Xamarin.UITest;
using NUnit.Framework;
#endif
namespace Xamarin.Forms.Controls.Issues
{
#if UITEST
[Category(UITestCategories.Image)]
#endif
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 8821, "Animations of downloaded gifs are not playing on Android", PlatformAffected.Android)]
public class Issue8821 : TestContentPage
{
Image _image;
public Issue8821()
{
var instructions = new Label
{
BackgroundColor = Color.Black,
TextColor = Color.White,
Text = "Press the DownloadFile button and then the Animate button. Verify that the gif is downloaded and animate without problems."
};
var downloadButton = new Button { Text = "DownloadFile" };
downloadButton.Clicked += async (sender, args) =>
{
string nextURL = "https://upload.wikimedia.org/wikipedia/commons/c/c0/An_example_animation_made_with_Pivot.gif";
await CreateImage(nextURL);
};
_image = new Image { Source = string.Empty };
var animateButton = new Button { Text = "Animate" };
animateButton.Clicked += (sender, args) =>
{
_image.IsAnimationPlaying = true;
};
Content = new StackLayout
{
Padding = new Thickness(20, 35, 20, 20),
Children =
{
instructions,
downloadButton,
_image,
animateButton
}
};
}
public string SecondImageSource { get; set; }
protected override void Init()
{
Title = "Issue 8821";
}
async Task CreateImage(string imageUrl)
{
var bytes = await DownloadImageAsync(imageUrl);
string path;
#if WINDOWS_UWP
path = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
#else
path = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
#endif
SecondImageSource = Path.Combine(path, "Issue8821.gif");
File.WriteAllBytes(SecondImageSource, bytes);
_image.Source = SecondImageSource;
OnPropertyChanged(nameof(SecondImageSource));
}
async Task<byte[]> DownloadImageAsync(string imageUrl)
{
try
{
using (var httpClient = new HttpClient())
using (var httpResponse = await httpClient.GetAsync(imageUrl))
{
if (httpResponse.StatusCode == HttpStatusCode.OK)
return await httpResponse.Content.ReadAsByteArrayAsync();
else
return null;
}
}
catch
{
return null;
}
}
}
}

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

@ -693,6 +693,7 @@ namespace Xamarin.Forms.Controls
item.Title = shellItemTitle; item.Title = shellItemTitle;
TShellSection shellSection = Activator.CreateInstance<TShellSection>(); TShellSection shellSection = Activator.CreateInstance<TShellSection>();
shellSection.Title = shellItemTitle;
shellSection.Items.Add(new ShellContent() shellSection.Items.Add(new ShellContent()
{ {

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

@ -14,6 +14,7 @@
<DependentUpon>Issue3228.xaml</DependentUpon> <DependentUpon>Issue3228.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue8262.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8207.xaml.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue8207.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue6362.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue6362.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue7505.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue7505.cs" />
@ -27,6 +28,7 @@
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewHeaderFooterView.cs" /> <Compile Include="$(MSBuildThisFileDirectory)CollectionViewHeaderFooterView.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewItemsUpdatingScrollMode.cs" /> <Compile Include="$(MSBuildThisFileDirectory)CollectionViewItemsUpdatingScrollMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue4606.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue4606.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8644.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8177.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue8177.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue4744.xaml.cs"> <Compile Include="$(MSBuildThisFileDirectory)Issue4744.xaml.cs">
<DependentUpon>Issue4744.xaml</DependentUpon> <DependentUpon>Issue4744.xaml</DependentUpon>
@ -148,6 +150,7 @@
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue7963.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue7963.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8741.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RefreshViewTests.cs" /> <Compile Include="$(MSBuildThisFileDirectory)RefreshViewTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue7338.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue7338.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ScrollToGroup.cs" /> <Compile Include="$(MSBuildThisFileDirectory)ScrollToGroup.cs" />
@ -1213,9 +1216,11 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue8638.xaml.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue8638.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8392.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue8392.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8672.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue8672.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8821.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8326.xaml.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue8326.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8449.xaml.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue8449.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue7875.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Issue7875.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8461.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla22229.xaml"> <EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla22229.xaml">

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

@ -329,5 +329,16 @@ namespace Xamarin.Forms.Core.UnitTests
{ {
Assert.AreEqual(Color.Default, (Color)System.Drawing.Color.Empty); Assert.AreEqual(Color.Default, (Color)System.Drawing.Color.Empty);
} }
[Test]
public void DefaultColorsMatch()
{
//This spot-checks a few of the fields in Color
Assert.AreEqual(Color.CornflowerBlue, Color.FromRgb(100, 149, 237));
Assert.AreEqual(Color.DarkSalmon, Color.FromRgb(233, 150, 122));
Assert.AreEqual(Color.Transparent, Color.FromRgba(255, 255, 255, 0));
Assert.AreEqual(Color.Wheat, Color.FromRgb(245, 222, 179));
Assert.AreEqual(Color.White, Color.FromRgb(255, 255, 255));
}
} }
} }

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

@ -0,0 +1,36 @@
using System;
using NUnit.Framework;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Core.UnitTests
{
[TestFixture]
public class NumericExtensionsTests
{
[Test]
public void InRange()
{
Assert.AreEqual(5, 5.Clamp(0, 10));
}
[Test]
public void BelowMin()
{
Assert.AreEqual(5, 0.Clamp(5, 10));
}
[Test]
public void AboveMax()
{
Assert.AreEqual(5, 10.Clamp(0, 5));
}
[Test]
public void MinMaxWrong()
{
Assert.AreEqual(0, 10.Clamp(5, 0));
Assert.AreEqual(0, 5.Clamp(10, 0));
Assert.AreEqual(5, 0.Clamp(10, 5));
}
}
}

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

@ -76,6 +76,7 @@
<Compile Include="CommandSourceTests.cs" /> <Compile Include="CommandSourceTests.cs" />
<Compile Include="CommandTests.cs" /> <Compile Include="CommandTests.cs" />
<Compile Include="DependencyResolutionTests.cs" /> <Compile Include="DependencyResolutionTests.cs" />
<Compile Include="NumericExtensionsTests.cs" />
<Compile Include="RefreshViewTests.cs" /> <Compile Include="RefreshViewTests.cs" />
<Compile Include="MockDispatcherProvider.cs" /> <Compile Include="MockDispatcherProvider.cs" />
<Compile Include="MockDispatcher.cs" /> <Compile Include="MockDispatcher.cs" />

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

@ -279,15 +279,16 @@ namespace Xamarin.Forms
return pi; return pi;
} }
//defined on a base class ?
if (sourceType.BaseType is Type baseT && GetIndexer(baseT.GetTypeInfo(), indexerName, content) is PropertyInfo p)
return p;
//defined on an interface ? //defined on an interface ?
foreach (var face in sourceType.ImplementedInterfaces) { foreach (var face in sourceType.ImplementedInterfaces) {
if (GetIndexer(face.GetTypeInfo(), indexerName, content) is PropertyInfo pi) if (GetIndexer(face.GetTypeInfo(), indexerName, content) is PropertyInfo pi)
return pi; return pi;
} }
//defined on a base class ?
if (sourceType.BaseType is Type baseT && GetIndexer(baseT.GetTypeInfo(), indexerName, content) is PropertyInfo p)
return p;
return null; return null;
} }

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

@ -114,6 +114,26 @@ namespace Xamarin.Forms
} }
} }
Color(int r, int g, int b)
{
_mode = Mode.Rgb;
_r = r / 255f;
_g = g / 255f;
_b = b / 255f;
_a = 1;
ConvertToHsl(_r, _g, _b, _mode, out _hue, out _saturation, out _luminosity);
}
Color(int r, int g, int b, int a)
{
_mode = Mode.Rgb;
_r = r / 255f;
_g = g / 255f;
_b = b / 255f;
_a = a / 255f;
ConvertToHsl(_r, _g, _b, _mode, out _hue, out _saturation, out _luminosity);
}
public Color(double r, double g, double b) : this(r, g, b, 1) public Color(double r, double g, double b) : this(r, g, b, 1)
{ {
} }
@ -418,150 +438,150 @@ namespace Xamarin.Forms
#region Color Definitions #region Color Definitions
// matches colors in WPF's System.Windows.Media.Colors // matches colors in WPF's System.Windows.Media.Colors
public static readonly Color AliceBlue = FromRgb(240, 248, 255); public static readonly Color AliceBlue = new Color(240, 248, 255);
public static readonly Color AntiqueWhite = FromRgb(250, 235, 215); public static readonly Color AntiqueWhite = new Color(250, 235, 215);
public static readonly Color Aqua = FromRgb(0, 255, 255); public static readonly Color Aqua = new Color(0, 255, 255);
public static readonly Color Aquamarine = FromRgb(127, 255, 212); public static readonly Color Aquamarine = new Color(127, 255, 212);
public static readonly Color Azure = FromRgb(240, 255, 255); public static readonly Color Azure = new Color(240, 255, 255);
public static readonly Color Beige = FromRgb(245, 245, 220); public static readonly Color Beige = new Color(245, 245, 220);
public static readonly Color Bisque = FromRgb(255, 228, 196); public static readonly Color Bisque = new Color(255, 228, 196);
public static readonly Color Black = FromRgb(0, 0, 0); public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color BlanchedAlmond = FromRgb(255, 235, 205); public static readonly Color BlanchedAlmond = new Color(255, 235, 205);
public static readonly Color Blue = FromRgb(0, 0, 255); public static readonly Color Blue = new Color(0, 0, 255);
public static readonly Color BlueViolet = FromRgb(138, 43, 226); public static readonly Color BlueViolet = new Color(138, 43, 226);
public static readonly Color Brown = FromRgb(165, 42, 42); public static readonly Color Brown = new Color(165, 42, 42);
public static readonly Color BurlyWood = FromRgb(222, 184, 135); public static readonly Color BurlyWood = new Color(222, 184, 135);
public static readonly Color CadetBlue = FromRgb(95, 158, 160); public static readonly Color CadetBlue = new Color(95, 158, 160);
public static readonly Color Chartreuse = FromRgb(127, 255, 0); public static readonly Color Chartreuse = new Color(127, 255, 0);
public static readonly Color Chocolate = FromRgb(210, 105, 30); public static readonly Color Chocolate = new Color(210, 105, 30);
public static readonly Color Coral = FromRgb(255, 127, 80); public static readonly Color Coral = new Color(255, 127, 80);
public static readonly Color CornflowerBlue = FromRgb(100, 149, 237); public static readonly Color CornflowerBlue = new Color(100, 149, 237);
public static readonly Color Cornsilk = FromRgb(255, 248, 220); public static readonly Color Cornsilk = new Color(255, 248, 220);
public static readonly Color Crimson = FromRgb(220, 20, 60); public static readonly Color Crimson = new Color(220, 20, 60);
public static readonly Color Cyan = FromRgb(0, 255, 255); public static readonly Color Cyan = new Color(0, 255, 255);
public static readonly Color DarkBlue = FromRgb(0, 0, 139); public static readonly Color DarkBlue = new Color(0, 0, 139);
public static readonly Color DarkCyan = FromRgb(0, 139, 139); public static readonly Color DarkCyan = new Color(0, 139, 139);
public static readonly Color DarkGoldenrod = FromRgb(184, 134, 11); public static readonly Color DarkGoldenrod = new Color(184, 134, 11);
public static readonly Color DarkGray = FromRgb(169, 169, 169); public static readonly Color DarkGray = new Color(169, 169, 169);
public static readonly Color DarkGreen = FromRgb(0, 100, 0); public static readonly Color DarkGreen = new Color(0, 100, 0);
public static readonly Color DarkKhaki = FromRgb(189, 183, 107); public static readonly Color DarkKhaki = new Color(189, 183, 107);
public static readonly Color DarkMagenta = FromRgb(139, 0, 139); public static readonly Color DarkMagenta = new Color(139, 0, 139);
public static readonly Color DarkOliveGreen = FromRgb(85, 107, 47); public static readonly Color DarkOliveGreen = new Color(85, 107, 47);
public static readonly Color DarkOrange = FromRgb(255, 140, 0); public static readonly Color DarkOrange = new Color(255, 140, 0);
public static readonly Color DarkOrchid = FromRgb(153, 50, 204); public static readonly Color DarkOrchid = new Color(153, 50, 204);
public static readonly Color DarkRed = FromRgb(139, 0, 0); public static readonly Color DarkRed = new Color(139, 0, 0);
public static readonly Color DarkSalmon = FromRgb(233, 150, 122); public static readonly Color DarkSalmon = new Color(233, 150, 122);
public static readonly Color DarkSeaGreen = FromRgb(143, 188, 143); public static readonly Color DarkSeaGreen = new Color(143, 188, 143);
public static readonly Color DarkSlateBlue = FromRgb(72, 61, 139); public static readonly Color DarkSlateBlue = new Color(72, 61, 139);
public static readonly Color DarkSlateGray = FromRgb(47, 79, 79); public static readonly Color DarkSlateGray = new Color(47, 79, 79);
public static readonly Color DarkTurquoise = FromRgb(0, 206, 209); public static readonly Color DarkTurquoise = new Color(0, 206, 209);
public static readonly Color DarkViolet = FromRgb(148, 0, 211); public static readonly Color DarkViolet = new Color(148, 0, 211);
public static readonly Color DeepPink = FromRgb(255, 20, 147); public static readonly Color DeepPink = new Color(255, 20, 147);
public static readonly Color DeepSkyBlue = FromRgb(0, 191, 255); public static readonly Color DeepSkyBlue = new Color(0, 191, 255);
public static readonly Color DimGray = FromRgb(105, 105, 105); public static readonly Color DimGray = new Color(105, 105, 105);
public static readonly Color DodgerBlue = FromRgb(30, 144, 255); public static readonly Color DodgerBlue = new Color(30, 144, 255);
public static readonly Color Firebrick = FromRgb(178, 34, 34); public static readonly Color Firebrick = new Color(178, 34, 34);
public static readonly Color FloralWhite = FromRgb(255, 250, 240); public static readonly Color FloralWhite = new Color(255, 250, 240);
public static readonly Color ForestGreen = FromRgb(34, 139, 34); public static readonly Color ForestGreen = new Color(34, 139, 34);
public static readonly Color Fuchsia = FromRgb(255, 0, 255); public static readonly Color Fuchsia = new Color(255, 0, 255);
[Obsolete("Fuschia is obsolete as of version 1.3.0. Please use Fuchsia instead.")] [Obsolete("Fuschia is obsolete as of version 1.3.0. Please use Fuchsia instead.")]
[EditorBrowsable(EditorBrowsableState.Never)] [EditorBrowsable(EditorBrowsableState.Never)]
public static readonly Color Fuschia = FromRgb(255, 0, 255); public static readonly Color Fuschia = new Color(255, 0, 255);
public static readonly Color Gainsboro = FromRgb(220, 220, 220); public static readonly Color Gainsboro = new Color(220, 220, 220);
public static readonly Color GhostWhite = FromRgb(248, 248, 255); public static readonly Color GhostWhite = new Color(248, 248, 255);
public static readonly Color Gold = FromRgb(255, 215, 0); public static readonly Color Gold = new Color(255, 215, 0);
public static readonly Color Goldenrod = FromRgb(218, 165, 32); public static readonly Color Goldenrod = new Color(218, 165, 32);
public static readonly Color Gray = FromRgb(128, 128, 128); public static readonly Color Gray = new Color(128, 128, 128);
public static readonly Color Green = FromRgb(0, 128, 0); public static readonly Color Green = new Color(0, 128, 0);
public static readonly Color GreenYellow = FromRgb(173, 255, 47); public static readonly Color GreenYellow = new Color(173, 255, 47);
public static readonly Color Honeydew = FromRgb(240, 255, 240); public static readonly Color Honeydew = new Color(240, 255, 240);
public static readonly Color HotPink = FromRgb(255, 105, 180); public static readonly Color HotPink = new Color(255, 105, 180);
public static readonly Color IndianRed = FromRgb(205, 92, 92); public static readonly Color IndianRed = new Color(205, 92, 92);
public static readonly Color Indigo = FromRgb(75, 0, 130); public static readonly Color Indigo = new Color(75, 0, 130);
public static readonly Color Ivory = FromRgb(255, 255, 240); public static readonly Color Ivory = new Color(255, 255, 240);
public static readonly Color Khaki = FromRgb(240, 230, 140); public static readonly Color Khaki = new Color(240, 230, 140);
public static readonly Color Lavender = FromRgb(230, 230, 250); public static readonly Color Lavender = new Color(230, 230, 250);
public static readonly Color LavenderBlush = FromRgb(255, 240, 245); public static readonly Color LavenderBlush = new Color(255, 240, 245);
public static readonly Color LawnGreen = FromRgb(124, 252, 0); public static readonly Color LawnGreen = new Color(124, 252, 0);
public static readonly Color LemonChiffon = FromRgb(255, 250, 205); public static readonly Color LemonChiffon = new Color(255, 250, 205);
public static readonly Color LightBlue = FromRgb(173, 216, 230); public static readonly Color LightBlue = new Color(173, 216, 230);
public static readonly Color LightCoral = FromRgb(240, 128, 128); public static readonly Color LightCoral = new Color(240, 128, 128);
public static readonly Color LightCyan = FromRgb(224, 255, 255); public static readonly Color LightCyan = new Color(224, 255, 255);
public static readonly Color LightGoldenrodYellow = FromRgb(250, 250, 210); public static readonly Color LightGoldenrodYellow = new Color(250, 250, 210);
public static readonly Color LightGray = FromRgb(211, 211, 211); public static readonly Color LightGray = new Color(211, 211, 211);
public static readonly Color LightGreen = FromRgb(144, 238, 144); public static readonly Color LightGreen = new Color(144, 238, 144);
public static readonly Color LightPink = FromRgb(255, 182, 193); public static readonly Color LightPink = new Color(255, 182, 193);
public static readonly Color LightSalmon = FromRgb(255, 160, 122); public static readonly Color LightSalmon = new Color(255, 160, 122);
public static readonly Color LightSeaGreen = FromRgb(32, 178, 170); public static readonly Color LightSeaGreen = new Color(32, 178, 170);
public static readonly Color LightSkyBlue = FromRgb(135, 206, 250); public static readonly Color LightSkyBlue = new Color(135, 206, 250);
public static readonly Color LightSlateGray = FromRgb(119, 136, 153); public static readonly Color LightSlateGray = new Color(119, 136, 153);
public static readonly Color LightSteelBlue = FromRgb(176, 196, 222); public static readonly Color LightSteelBlue = new Color(176, 196, 222);
public static readonly Color LightYellow = FromRgb(255, 255, 224); public static readonly Color LightYellow = new Color(255, 255, 224);
public static readonly Color Lime = FromRgb(0, 255, 0); public static readonly Color Lime = new Color(0, 255, 0);
public static readonly Color LimeGreen = FromRgb(50, 205, 50); public static readonly Color LimeGreen = new Color(50, 205, 50);
public static readonly Color Linen = FromRgb(250, 240, 230); public static readonly Color Linen = new Color(250, 240, 230);
public static readonly Color Magenta = FromRgb(255, 0, 255); public static readonly Color Magenta = new Color(255, 0, 255);
public static readonly Color Maroon = FromRgb(128, 0, 0); public static readonly Color Maroon = new Color(128, 0, 0);
public static readonly Color MediumAquamarine = FromRgb(102, 205, 170); public static readonly Color MediumAquamarine = new Color(102, 205, 170);
public static readonly Color MediumBlue = FromRgb(0, 0, 205); public static readonly Color MediumBlue = new Color(0, 0, 205);
public static readonly Color MediumOrchid = FromRgb(186, 85, 211); public static readonly Color MediumOrchid = new Color(186, 85, 211);
public static readonly Color MediumPurple = FromRgb(147, 112, 219); public static readonly Color MediumPurple = new Color(147, 112, 219);
public static readonly Color MediumSeaGreen = FromRgb(60, 179, 113); public static readonly Color MediumSeaGreen = new Color(60, 179, 113);
public static readonly Color MediumSlateBlue = FromRgb(123, 104, 238); public static readonly Color MediumSlateBlue = new Color(123, 104, 238);
public static readonly Color MediumSpringGreen = FromRgb(0, 250, 154); public static readonly Color MediumSpringGreen = new Color(0, 250, 154);
public static readonly Color MediumTurquoise = FromRgb(72, 209, 204); public static readonly Color MediumTurquoise = new Color(72, 209, 204);
public static readonly Color MediumVioletRed = FromRgb(199, 21, 133); public static readonly Color MediumVioletRed = new Color(199, 21, 133);
public static readonly Color MidnightBlue = FromRgb(25, 25, 112); public static readonly Color MidnightBlue = new Color(25, 25, 112);
public static readonly Color MintCream = FromRgb(245, 255, 250); public static readonly Color MintCream = new Color(245, 255, 250);
public static readonly Color MistyRose = FromRgb(255, 228, 225); public static readonly Color MistyRose = new Color(255, 228, 225);
public static readonly Color Moccasin = FromRgb(255, 228, 181); public static readonly Color Moccasin = new Color(255, 228, 181);
public static readonly Color NavajoWhite = FromRgb(255, 222, 173); public static readonly Color NavajoWhite = new Color(255, 222, 173);
public static readonly Color Navy = FromRgb(0, 0, 128); public static readonly Color Navy = new Color(0, 0, 128);
public static readonly Color OldLace = FromRgb(253, 245, 230); public static readonly Color OldLace = new Color(253, 245, 230);
public static readonly Color Olive = FromRgb(128, 128, 0); public static readonly Color Olive = new Color(128, 128, 0);
public static readonly Color OliveDrab = FromRgb(107, 142, 35); public static readonly Color OliveDrab = new Color(107, 142, 35);
public static readonly Color Orange = FromRgb(255, 165, 0); public static readonly Color Orange = new Color(255, 165, 0);
public static readonly Color OrangeRed = FromRgb(255, 69, 0); public static readonly Color OrangeRed = new Color(255, 69, 0);
public static readonly Color Orchid = FromRgb(218, 112, 214); public static readonly Color Orchid = new Color(218, 112, 214);
public static readonly Color PaleGoldenrod = FromRgb(238, 232, 170); public static readonly Color PaleGoldenrod = new Color(238, 232, 170);
public static readonly Color PaleGreen = FromRgb(152, 251, 152); public static readonly Color PaleGreen = new Color(152, 251, 152);
public static readonly Color PaleTurquoise = FromRgb(175, 238, 238); public static readonly Color PaleTurquoise = new Color(175, 238, 238);
public static readonly Color PaleVioletRed = FromRgb(219, 112, 147); public static readonly Color PaleVioletRed = new Color(219, 112, 147);
public static readonly Color PapayaWhip = FromRgb(255, 239, 213); public static readonly Color PapayaWhip = new Color(255, 239, 213);
public static readonly Color PeachPuff = FromRgb(255, 218, 185); public static readonly Color PeachPuff = new Color(255, 218, 185);
public static readonly Color Peru = FromRgb(205, 133, 63); public static readonly Color Peru = new Color(205, 133, 63);
public static readonly Color Pink = FromRgb(255, 192, 203); public static readonly Color Pink = new Color(255, 192, 203);
public static readonly Color Plum = FromRgb(221, 160, 221); public static readonly Color Plum = new Color(221, 160, 221);
public static readonly Color PowderBlue = FromRgb(176, 224, 230); public static readonly Color PowderBlue = new Color(176, 224, 230);
public static readonly Color Purple = FromRgb(128, 0, 128); public static readonly Color Purple = new Color(128, 0, 128);
public static readonly Color Red = FromRgb(255, 0, 0); public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color RosyBrown = FromRgb(188, 143, 143); public static readonly Color RosyBrown = new Color(188, 143, 143);
public static readonly Color RoyalBlue = FromRgb(65, 105, 225); public static readonly Color RoyalBlue = new Color(65, 105, 225);
public static readonly Color SaddleBrown = FromRgb(139, 69, 19); public static readonly Color SaddleBrown = new Color(139, 69, 19);
public static readonly Color Salmon = FromRgb(250, 128, 114); public static readonly Color Salmon = new Color(250, 128, 114);
public static readonly Color SandyBrown = FromRgb(244, 164, 96); public static readonly Color SandyBrown = new Color(244, 164, 96);
public static readonly Color SeaGreen = FromRgb(46, 139, 87); public static readonly Color SeaGreen = new Color(46, 139, 87);
public static readonly Color SeaShell = FromRgb(255, 245, 238); public static readonly Color SeaShell = new Color(255, 245, 238);
public static readonly Color Sienna = FromRgb(160, 82, 45); public static readonly Color Sienna = new Color(160, 82, 45);
public static readonly Color Silver = FromRgb(192, 192, 192); public static readonly Color Silver = new Color(192, 192, 192);
public static readonly Color SkyBlue = FromRgb(135, 206, 235); public static readonly Color SkyBlue = new Color(135, 206, 235);
public static readonly Color SlateBlue = FromRgb(106, 90, 205); public static readonly Color SlateBlue = new Color(106, 90, 205);
public static readonly Color SlateGray = FromRgb(112, 128, 144); public static readonly Color SlateGray = new Color(112, 128, 144);
public static readonly Color Snow = FromRgb(255, 250, 250); public static readonly Color Snow = new Color(255, 250, 250);
public static readonly Color SpringGreen = FromRgb(0, 255, 127); public static readonly Color SpringGreen = new Color(0, 255, 127);
public static readonly Color SteelBlue = FromRgb(70, 130, 180); public static readonly Color SteelBlue = new Color(70, 130, 180);
public static readonly Color Tan = FromRgb(210, 180, 140); public static readonly Color Tan = new Color(210, 180, 140);
public static readonly Color Teal = FromRgb(0, 128, 128); public static readonly Color Teal = new Color(0, 128, 128);
public static readonly Color Thistle = FromRgb(216, 191, 216); public static readonly Color Thistle = new Color(216, 191, 216);
public static readonly Color Tomato = FromRgb(255, 99, 71); public static readonly Color Tomato = new Color(255, 99, 71);
public static readonly Color Transparent = FromRgba(255, 255, 255, 0); public static readonly Color Transparent = new Color(255, 255, 255, 0);
public static readonly Color Turquoise = FromRgb(64, 224, 208); public static readonly Color Turquoise = new Color(64, 224, 208);
public static readonly Color Violet = FromRgb(238, 130, 238); public static readonly Color Violet = new Color(238, 130, 238);
public static readonly Color Wheat = FromRgb(245, 222, 179); public static readonly Color Wheat = new Color(245, 222, 179);
public static readonly Color White = FromRgb(255, 255, 255); public static readonly Color White = new Color(255, 255, 255);
public static readonly Color WhiteSmoke = FromRgb(245, 245, 245); public static readonly Color WhiteSmoke = new Color(245, 245, 245);
public static readonly Color Yellow = FromRgb(255, 255, 0); public static readonly Color Yellow = new Color(255, 255, 0);
public static readonly Color YellowGreen = FromRgb(154, 205, 50); public static readonly Color YellowGreen = new Color(154, 205, 50);
#endregion #endregion
} }

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

@ -109,33 +109,15 @@ namespace Xamarin.Forms
if (s_initialized) if (s_initialized)
return; return;
Type targetAttrType = typeof(DependencyAttribute);
// Don't use LINQ for performance reasons // Don't use LINQ for performance reasons
// Naive implementation can easily take over a second to run // Naive implementation can easily take over a second to run
foreach (Assembly assembly in assemblies) foreach (Assembly assembly in assemblies)
{ {
object[] attributes; object[] attributes = assembly.GetCustomAttributesSafe(typeof(DependencyAttribute));
try if (attributes == null)
{
#if NETSTANDARD2_0
attributes = assembly.GetCustomAttributes(targetAttrType, true);
#else
attributes = assembly.GetCustomAttributes(targetAttrType).ToArray();
#endif
}
catch (System.IO.FileNotFoundException)
{
// Sometimes the previewer doesn't actually have everything required for these loads to work
Log.Warning(nameof(Registrar), "Could not load assembly: {0} for Attibute {1} | Some renderers may not be loaded", assembly.FullName, targetAttrType.FullName);
continue;
}
var length = attributes.Length;
if (length == 0)
continue; continue;
for (int i = 0; i < length; i++) for (int i = 0; i < attributes.Length; i++)
{ {
DependencyAttribute attribute = (DependencyAttribute)attributes[i]; DependencyAttribute attribute = (DependencyAttribute)attributes[i];
if (!DependencyTypes.Contains(attribute.Implementor)) if (!DependencyTypes.Contains(attribute.Implementor))

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

@ -12,6 +12,11 @@ namespace Xamarin.Forms.Internals
{ {
int _masterDetails; int _masterDetails;
Page _target; Page _target;
ToolBarItemComparer _toolBarItemComparer;
public ToolbarTracker()
{
_toolBarItemComparer = new ToolBarItemComparer();
}
public IEnumerable<Page> AdditionalTargets { get; set; } public IEnumerable<Page> AdditionalTargets { get; set; }
@ -44,12 +49,20 @@ namespace Xamarin.Forms.Internals
get get
{ {
if (Target == null) if (Target == null)
return Enumerable.Empty<ToolbarItem>(); return new ToolbarItem[0];
IEnumerable<ToolbarItem> items = GetCurrentToolbarItems(Target);
if (AdditionalTargets != null)
items = items.Concat(AdditionalTargets.SelectMany(t => t.ToolbarItems));
return items.OrderBy(ti => ti.Priority); // I realize this is sorting on every single get but we don't have
// a mechanism in place currently to invalidate a stored version of this
List<ToolbarItem> returnValue = GetCurrentToolbarItems(Target);
if (AdditionalTargets != null)
foreach(var item in AdditionalTargets)
foreach(var toolbarItem in item.ToolbarItems)
returnValue.Add(toolbarItem);
returnValue.Sort(_toolBarItemComparer);
return returnValue;
} }
} }
@ -58,7 +71,7 @@ namespace Xamarin.Forms.Internals
void EmitCollectionChanged() void EmitCollectionChanged()
=> CollectionChanged?.Invoke(this, EventArgs.Empty); => CollectionChanged?.Invoke(this, EventArgs.Empty);
IEnumerable<ToolbarItem> GetCurrentToolbarItems(Page page) List<ToolbarItem> GetCurrentToolbarItems(Page page)
{ {
var result = new List<ToolbarItem>(); var result = new List<ToolbarItem>();
result.AddRange(page.ToolbarItems); result.AddRange(page.ToolbarItems);
@ -178,5 +191,10 @@ namespace Xamarin.Forms.Internals
page.DescendantRemoved -= OnChildRemoved; page.DescendantRemoved -= OnChildRemoved;
page.PropertyChanged -= OnPropertyChanged; page.PropertyChanged -= OnPropertyChanged;
} }
class ToolBarItemComparer : IComparer<ToolbarItem>
{
public int Compare(ToolbarItem x, ToolbarItem y) => x.Priority.CompareTo(y.Priority);
}
} }
} }

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

@ -1,20 +1,48 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Xamarin.Forms.Internals namespace Xamarin.Forms.Internals
{ {
[EditorBrowsable(EditorBrowsableState.Never)] [EditorBrowsable(EditorBrowsableState.Never)]
public static class NumericExtensions public static class NumericExtensions
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Clamp(this double self, double min, double max) public static double Clamp(this double self, double min, double max)
{ {
return Math.Min(max, Math.Max(self, min)); if (max < min)
{
return max;
}
else if (self < min)
{
return min;
}
else if (self > max)
{
return max;
} }
return self;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Clamp(this int self, int min, int max) public static int Clamp(this int self, int min, int max)
{ {
return Math.Min(max, Math.Max(self, min)); if (max < min)
{
return max;
}
else if (self < min)
{
return min;
}
else if (self > max)
{
return max;
}
return self;
} }
} }
} }

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

@ -6,6 +6,8 @@ namespace Xamarin.Forms.PlatformConfiguration.TizenSpecific
{ {
public static readonly BindableProperty BlendColorProperty = BindableProperty.Create("BlendColor", typeof(Color), typeof(FormsElement), Color.Default); public static readonly BindableProperty BlendColorProperty = BindableProperty.Create("BlendColor", typeof(Color), typeof(FormsElement), Color.Default);
public static readonly BindableProperty FileProperty = BindableProperty.Create("File", typeof(string), typeof(FormsElement), default(string));
public static Color GetBlendColor(BindableObject element) public static Color GetBlendColor(BindableObject element)
{ {
return (Color)element.GetValue(BlendColorProperty); return (Color)element.GetValue(BlendColorProperty);
@ -26,5 +28,26 @@ namespace Xamarin.Forms.PlatformConfiguration.TizenSpecific
SetBlendColor(config.Element, color); SetBlendColor(config.Element, color);
return config; return config;
} }
public static string GetFile(BindableObject element)
{
return (string)element.GetValue(FileProperty);
}
public static void SetFile(BindableObject element, string file)
{
element.SetValue(FileProperty, file);
}
public static string GetFile(this IPlatformElementConfiguration<Tizen, FormsElement> config)
{
return GetFile(config.Element);
}
public static IPlatformElementConfiguration<Tizen, FormsElement> SetFile(this IPlatformElementConfiguration<Tizen, FormsElement> config, string file)
{
SetFile(config.Element, file);
return config;
}
} }
} }

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

@ -47,13 +47,12 @@ namespace Xamarin.Forms.Internals
internal static object[] GetCustomAttributesSafe(this Assembly assembly, Type attrType) internal static object[] GetCustomAttributesSafe(this Assembly assembly, Type attrType)
{ {
object[] attributes = null;
try try
{ {
#if NETSTANDARD2_0 #if NETSTANDARD2_0
attributes = assembly.GetCustomAttributes(attrType, true); return assembly.GetCustomAttributes(attrType, true);
#else #else
attributes = assembly.GetCustomAttributes(attrType).ToArray(); return assembly.GetCustomAttributes(attrType).ToArray();
#endif #endif
} }
catch (System.IO.FileNotFoundException) catch (System.IO.FileNotFoundException)
@ -62,7 +61,7 @@ namespace Xamarin.Forms.Internals
Log.Warning(nameof(Registrar), "Could not load assembly: {0} for Attribute {1} | Some renderers may not be loaded", assembly.FullName, attrType.FullName); Log.Warning(nameof(Registrar), "Could not load assembly: {0} for Attribute {1} | Some renderers may not be loaded", assembly.FullName, attrType.FullName);
} }
return attributes; return null;
} }
public static Type[] GetExportedTypes(this Assembly assembly) public static Type[] GetExportedTypes(this Assembly assembly)

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

@ -336,19 +336,8 @@ namespace Xamarin.Forms.Internals
foreach (Type attrType in attrTypes) foreach (Type attrType in attrTypes)
{ {
object[] attributes; object[] attributes = assembly.GetCustomAttributesSafe(attrType);
try if (attributes == null || attributes.Length == 0)
{
#if NETSTANDARD2_0
attributes = assembly.GetCustomAttributes(attrType, true);
#else
attributes = assembly.GetCustomAttributes(attrType).ToArray();
#endif
}
catch (System.IO.FileNotFoundException)
{
// Sometimes the previewer doesn't actually have everything required for these loads to work
Log.Warning(nameof(Registrar), "Could not load assembly: {0} for Attibute {1} | Some renderers may not be loaded", assembly.FullName, attrType.FullName);
continue; continue;
} }
@ -369,19 +358,14 @@ namespace Xamarin.Forms.Internals
} }
} }
object[] effectAttributes = assembly.GetCustomAttributesSafe(typeof (ExportEffectAttribute));
if (effectAttributes == null || effectAttributes.Length == 0)
continue;
string resolutionName = assembly.FullName; string resolutionName = assembly.FullName;
var resolutionNameAttribute = (ResolutionGroupNameAttribute)assembly.GetCustomAttribute(typeof(ResolutionGroupNameAttribute)); var resolutionNameAttribute = (ResolutionGroupNameAttribute)assembly.GetCustomAttribute(typeof(ResolutionGroupNameAttribute));
if (resolutionNameAttribute != null) if (resolutionNameAttribute != null)
resolutionName = resolutionNameAttribute.ShortName; resolutionName = resolutionNameAttribute.ShortName;
RegisterEffects(resolutionName, (ExportEffectAttribute[])effectAttributes);
#if NETSTANDARD2_0
object[] effectAttributes = assembly.GetCustomAttributes(typeof(ExportEffectAttribute), true);
#else
object[] effectAttributes = assembly.GetCustomAttributes(typeof(ExportEffectAttribute)).ToArray();
#endif
var typedEffectAttributes = new ExportEffectAttribute[effectAttributes.Length];
Array.Copy(effectAttributes, typedEffectAttributes, effectAttributes.Length);
RegisterEffects(resolutionName, typedEffectAttributes);
Profile.FrameEnd(assemblyName); Profile.FrameEnd(assemblyName);
} }

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

@ -220,6 +220,6 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
} }
AppCompatButton IButtonLayoutRenderer.View => Control; AppCompatButton IButtonLayoutRenderer.View => Control;
bool IDisposedState.IsDisposed => _isDisposed; bool IDisposedState.IsDisposed => _isDisposed || !Control.IsAlive();
} }
} }

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

@ -27,7 +27,6 @@ namespace Xamarin.Forms.Platform.Android
CompoundButton.IOnCheckedChangeListener CompoundButton.IOnCheckedChangeListener
{ {
bool _disposed; bool _disposed;
bool _skipInvalidate;
int? _defaultLabelFor; int? _defaultLabelFor;
VisualElementTracker _tracker; VisualElementTracker _tracker;
VisualElementRenderer _visualElementRenderer; VisualElementRenderer _visualElementRenderer;
@ -87,17 +86,6 @@ namespace Xamarin.Forms.Platform.Android
base.Dispose(disposing); base.Dispose(disposing);
} }
public override void Invalidate()
{
if (_skipInvalidate)
{
_skipInvalidate = false;
return;
}
base.Invalidate();
}
Size MinimumSize() Size MinimumSize()
{ {
return new Size(); return new Size();

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

@ -23,7 +23,6 @@ namespace Xamarin.Forms.Platform.Android
ITabStop ITabStop
{ {
bool _disposed; bool _disposed;
bool _skipInvalidate;
int? _defaultLabelFor; int? _defaultLabelFor;
VisualElementTracker _tracker; VisualElementTracker _tracker;
VisualElementRenderer _visualElementRenderer; VisualElementRenderer _visualElementRenderer;
@ -85,17 +84,6 @@ namespace Xamarin.Forms.Platform.Android
base.Dispose(disposing); base.Dispose(disposing);
} }
public override void Invalidate()
{
if (_skipInvalidate)
{
_skipInvalidate = false;
return;
}
base.Invalidate();
}
Size MinimumSize() Size MinimumSize()
{ {
return Size.Zero; return Size.Zero;

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

@ -43,7 +43,7 @@ namespace Xamarin.Forms.Platform.Android
AView IVisualElementRenderer.View => this; AView IVisualElementRenderer.View => this;
ViewGroup IVisualElementRenderer.ViewGroup => null; ViewGroup IVisualElementRenderer.ViewGroup => null;
VisualElementTracker IVisualElementRenderer.Tracker => _tracker; VisualElementTracker IVisualElementRenderer.Tracker => _tracker;
bool IDisposedState.IsDisposed => _disposed; bool IDisposedState.IsDisposed => ((IImageRendererController)this).IsDisposed;
public ImageButton Element public ImageButton Element
{ {
@ -56,7 +56,7 @@ namespace Xamarin.Forms.Platform.Android
} }
void IImageRendererController.SkipInvalidate() => _skipInvalidate = true; void IImageRendererController.SkipInvalidate() => _skipInvalidate = true;
bool IImageRendererController.IsDisposed => _disposed; bool IImageRendererController.IsDisposed => _disposed || !Control.IsAlive();
AppCompatImageButton Control => this; AppCompatImageButton Control => this;
public ImageButtonRenderer(Context context) : base(context) public ImageButtonRenderer(Context context) : base(context)

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

@ -32,8 +32,6 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
{ {
public class NavigationPageRenderer : VisualElementRenderer<NavigationPage>, IManageFragments, IOnClickListener, ILifeCycleState public class NavigationPageRenderer : VisualElementRenderer<NavigationPage>, IManageFragments, IOnClickListener, ILifeCycleState
{ {
const int DefaultDisabledToolbarAlpha = 127;
readonly List<Fragment> _fragmentStack = new List<Fragment>(); readonly List<Fragment> _fragmentStack = new List<Fragment>();
Drawable _backgroundDrawable; Drawable _backgroundDrawable;
@ -220,8 +218,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
{ {
_toolbarTracker.CollectionChanged -= ToolbarTrackerOnCollectionChanged; _toolbarTracker.CollectionChanged -= ToolbarTrackerOnCollectionChanged;
foreach (ToolbarItem item in _toolbarTracker.ToolbarItems) _toolbar.DisposeMenuItems(_toolbarTracker?.ToolbarItems, OnToolbarItemPropertyChanged);
item.PropertyChanged -= OnToolbarItemPropertyChanged;
_toolbarTracker.Target = null; _toolbarTracker.Target = null;
_toolbarTracker = null; _toolbarTracker = null;
@ -562,8 +559,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
protected virtual void OnToolbarItemPropertyChanged(object sender, PropertyChangedEventArgs e) protected virtual void OnToolbarItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{ {
if (e.PropertyName == MenuItem.IsEnabledProperty.PropertyName || e.PropertyName == MenuItem.TextProperty.PropertyName || e.PropertyName == MenuItem.IconImageSourceProperty.PropertyName) _toolbar.OnToolbarItemPropertyChanged(e, _toolbarTracker?.ToolbarItems, Context, null, OnToolbarItemPropertyChanged);
UpdateMenu();
} }
void InsertPageBefore(Page page, Page before) void InsertPageBefore(Page page, Page before)
@ -909,51 +905,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
if (_disposed) if (_disposed)
return; return;
AToolbar bar = _toolbar; _toolbar.UpdateMenuItems(_toolbarTracker?.ToolbarItems, Context, null, OnToolbarItemPropertyChanged);
Context context = Context;
IMenu menu = bar.Menu;
foreach (ToolbarItem item in _toolbarTracker.ToolbarItems)
item.PropertyChanged -= OnToolbarItemPropertyChanged;
menu.Clear();
foreach (ToolbarItem item in _toolbarTracker.ToolbarItems)
{
IMenuItemController controller = item;
item.PropertyChanged += OnToolbarItemPropertyChanged;
if (item.Order == ToolbarItemOrder.Secondary)
{
IMenuItem menuItem = menu.Add(item.Text);
menuItem.SetEnabled(controller.IsEnabled);
menuItem.SetOnMenuItemClickListener(new GenericMenuClickListener(controller.Activate));
menuItem.SetTitleOrContentDescription(item);
}
else
{
IMenuItem menuItem = menu.Add(item.Text);
menuItem.SetEnabled(controller.IsEnabled);
UpdateMenuItemIcon(context, menuItem, item);
menuItem.SetShowAsAction(ShowAsAction.Always);
menuItem.SetOnMenuItemClickListener(new GenericMenuClickListener(controller.Activate));
menuItem.SetTitleOrContentDescription(item);
}
}
}
protected virtual void UpdateMenuItemIcon(Context context, IMenuItem menuItem, ToolbarItem toolBarItem)
{
_ = this.ApplyDrawableAsync(toolBarItem, ToolbarItem.IconImageSourceProperty, Context, iconDrawable =>
{
if (iconDrawable != null)
{
if (!menuItem.IsEnabled)
{
iconDrawable.Mutate().SetAlpha(DefaultDisabledToolbarAlpha);
}
menuItem.SetIcon(iconDrawable);
}
});
} }
void UpdateToolbar() void UpdateToolbar()

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

@ -0,0 +1,111 @@
using System.ComponentModel;
using Android.Views;
using AToolbar = Android.Support.V7.Widget.Toolbar;
using ATextView = global::Android.Widget.TextView;
using Android.Content;
using Android.Graphics;
using System.Collections.Generic;
namespace Xamarin.Forms.Platform.Android
{
internal static class ToolbarExtensions
{
const int DefaultDisabledToolbarAlpha = 127;
public static void DisposeMenuItems(this AToolbar toolbar, IEnumerable<ToolbarItem> toolbarItems, PropertyChangedEventHandler toolbarItemChanged)
{
if (toolbarItems == null)
return;
foreach (var item in toolbarItems)
item.PropertyChanged -= toolbarItemChanged;
}
public static void UpdateMenuItems(this AToolbar toolbar,
IEnumerable<ToolbarItem> toolbarItems,
Context context,
Color? tintColor,
PropertyChangedEventHandler toolbarItemChanged
)
{
if (toolbarItems == null)
return;
var menu = toolbar.Menu;
menu.Clear();
foreach (var item in toolbarItems)
{
item.PropertyChanged -= toolbarItemChanged;
item.PropertyChanged += toolbarItemChanged;
using (var title = new Java.Lang.String(item.Text))
{
var menuitem = menu.Add(global::Android.Views.Menu.None, 0, item.Priority, title);
menuitem.SetEnabled(item.IsEnabled);
menuitem.SetTitleOrContentDescription(item);
UpdateMenuItemIcon(context, menuitem, item, tintColor);
if (item.Order != ToolbarItemOrder.Secondary)
menuitem.SetShowAsAction(ShowAsAction.Always);
menuitem.SetOnMenuItemClickListener(new GenericMenuClickListener(((IMenuItemController)item).Activate));
if (tintColor != null && tintColor != Color.Default)
{
var view = toolbar.FindViewById(menuitem.ItemId);
if (view is ATextView textView)
{
if (item.IsEnabled)
textView.SetTextColor(tintColor.Value.ToAndroid());
else
textView.SetTextColor(tintColor.Value.MultiplyAlpha(0.302).ToAndroid());
}
}
menuitem.Dispose();
}
}
}
static void UpdateMenuItemIcon(Context context, IMenuItem menuItem, ToolbarItem toolBarItem, Color? tintColor)
{
_ = context.ApplyDrawableAsync(toolBarItem, ToolbarItem.IconImageSourceProperty, baseDrawable =>
{
if (baseDrawable != null)
{
using (var constant = baseDrawable.GetConstantState())
using (var newDrawable = constant.NewDrawable())
using (var iconDrawable = newDrawable.Mutate())
{
if(tintColor != null)
iconDrawable.SetColorFilter(tintColor.Value.ToAndroid(Color.White), PorterDuff.Mode.SrcAtop);
if (!menuItem.IsEnabled)
{
iconDrawable.Mutate().SetAlpha(DefaultDisabledToolbarAlpha);
}
menuItem.SetIcon(iconDrawable);
}
}
});
}
public static void OnToolbarItemPropertyChanged(
this AToolbar toolbar,
PropertyChangedEventArgs e,
IEnumerable<ToolbarItem> toolbarItems,
Context context,
Color? tintColor,
PropertyChangedEventHandler toolbarItemChanged)
{
if (toolbarItems == null)
return;
if (e.IsOneOf(MenuItem.TextProperty, MenuItem.IconImageSourceProperty, MenuItem.IsEnabledProperty))
{
toolbar.UpdateMenuItems(toolbarItems, context, tintColor, toolbarItemChanged);
}
}
}
}

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

@ -51,14 +51,21 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
var oldImageElementManager = e.OldElement as IImageElement; var oldImageElementManager = e.OldElement as IImageElement;
var rendererController = renderer as IImageRendererController; var rendererController = renderer as IImageRendererController;
if (rendererController.IsDisposed)
return;
await TryUpdateBitmap(rendererController, view, newImageElementManager, oldImageElementManager); await TryUpdateBitmap(rendererController, view, newImageElementManager, oldImageElementManager);
if (rendererController.IsDisposed)
return;
UpdateAspect(rendererController, view, newImageElementManager, oldImageElementManager); UpdateAspect(rendererController, view, newImageElementManager, oldImageElementManager);
if (!rendererController.IsDisposed) if (rendererController.IsDisposed)
{ return;
ElevationHelper.SetElevation(view, renderer.Element); ElevationHelper.SetElevation(view, renderer.Element);
} }
}
async static void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) async static void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{ {
@ -136,6 +143,9 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
imageController.SetIsLoading(false); imageController.SetIsLoading(false);
} }
if (rendererController.IsDisposed)
return;
if (Control.Drawable is FormsAnimationDrawable updatedAnimation) if (Control.Drawable is FormsAnimationDrawable updatedAnimation)
{ {
rendererController.SetFormsAnimationDrawable(updatedAnimation); rendererController.SetFormsAnimationDrawable(updatedAnimation);

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

@ -23,7 +23,7 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
readonly MotionEventHelper _motionEventHelper = new MotionEventHelper(); readonly MotionEventHelper _motionEventHelper = new MotionEventHelper();
IFormsAnimationDrawable _formsAnimationDrawable; IFormsAnimationDrawable _formsAnimationDrawable;
bool IImageRendererController.IsDisposed => _disposed; bool IImageRendererController.IsDisposed => _disposed || !Control.IsAlive();
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if (_disposed) if (_disposed)

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

@ -249,7 +249,6 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
e.NewElement.PropertyChanged += OnElementPropertyChanged; e.NewElement.PropertyChanged += OnElementPropertyChanged;
SkipNextInvalidate();
UpdateText(); UpdateText();
UpdateLineHeight(); UpdateLineHeight();
UpdateCharacterSpacing(); UpdateCharacterSpacing();

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

@ -405,14 +405,15 @@ namespace Xamarin.Forms.Platform.Android
return; return;
} }
foreach (ToolbarItem item in _toolbarTracker.ToolbarItems) var toolbarItems = _toolbarTracker.ToolbarItems;
foreach (ToolbarItem item in toolbarItems)
item.PropertyChanged -= HandleToolbarItemPropertyChanged; item.PropertyChanged -= HandleToolbarItemPropertyChanged;
menu.Clear(); menu.Clear();
if (!ShouldShowActionBarTitleArea()) if (!ShouldShowActionBarTitleArea())
return; return;
foreach (ToolbarItem item in _toolbarTracker.ToolbarItems) foreach (ToolbarItem item in toolbarItems)
{ {
IMenuItemController controller = item; IMenuItemController controller = item;
item.PropertyChanged += HandleToolbarItemPropertyChanged; item.PropertyChanged += HandleToolbarItemPropertyChanged;

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

@ -38,6 +38,8 @@ namespace Xamarin.Forms.Platform.Android
public class FormsAnimationDrawable : AnimationDrawable, IFormsAnimationDrawable public class FormsAnimationDrawable : AnimationDrawable, IFormsAnimationDrawable
{ {
const int DefaultBufferSize = 4096;
int _repeatCounter = 0; int _repeatCounter = 0;
int _frameCount = 0; int _frameCount = 0;
bool _finished = false; bool _finished = false;
@ -192,28 +194,19 @@ namespace Xamarin.Forms.Platform.Android
InJustDecodeBounds = true InJustDecodeBounds = true
}; };
if (!FileImageSourceHandler.DecodeSynchronously) int drawableIdentifier = ResourceManager.GetDrawableByName(file);
await BitmapFactory.DecodeResourceAsync(context.Resources, ResourceManager.GetDrawableByName(file), options);
else
BitmapFactory.DecodeResource(context.Resources, ResourceManager.GetDrawableByName(file), options);
using (var stream = context.Resources.OpenRawResource(ResourceManager.GetDrawableByName(file))) if (drawableIdentifier != 0)
using (var decoder = new AndroidGIFImageParser(context, options.InDensity, options.InTargetDensity))
{
try
{ {
if (!FileImageSourceHandler.DecodeSynchronously) if (!FileImageSourceHandler.DecodeSynchronously)
await decoder.ParseAsync(stream).ConfigureAwait(false); await BitmapFactory.DecodeResourceAsync(context.Resources, drawableIdentifier, options);
else else
decoder.ParseAsync(stream).Wait(); BitmapFactory.DecodeResource(context.Resources, drawableIdentifier, options);
animation = decoder.Animation; animation = await GetFormsAnimationDrawableFromResource(drawableIdentifier, context, options);
}
catch (GIFDecoderFormatException)
{
animation = null;
}
} }
else
animation = await GetFormsAnimationDrawableFromFile(file, context, options);
if (animation == null) if (animation == null)
{ {
@ -264,6 +257,50 @@ namespace Xamarin.Forms.Platform.Android
return animation; return animation;
} }
internal static async Task<FormsAnimationDrawable> GetFormsAnimationDrawableFromResource(int resourceId, Context context, BitmapFactory.Options options)
{
FormsAnimationDrawable animation = null;
using (var stream = context.Resources.OpenRawResource(resourceId))
animation = await GetFormsAnimationDrawableFromStream(stream, context, options);
return animation;
}
internal static async Task<FormsAnimationDrawable> GetFormsAnimationDrawableFromFile(string file, Context context, BitmapFactory.Options options)
{
FormsAnimationDrawable animation = null;
using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultBufferSize, true))
animation = await GetFormsAnimationDrawableFromStream(stream, context, options);
return animation;
}
internal static async Task<FormsAnimationDrawable> GetFormsAnimationDrawableFromStream(Stream stream, Context context, BitmapFactory.Options options)
{
FormsAnimationDrawable animation = null;
using (var decoder = new AndroidGIFImageParser(context, options.InDensity, options.InTargetDensity))
{
try
{
if (!FileImageSourceHandler.DecodeSynchronously)
await decoder.ParseAsync(stream).ConfigureAwait(false);
else
decoder.ParseAsync(stream).Wait();
animation = decoder.Animation;
}
catch (GIFDecoderFormatException)
{
animation = null;
}
}
return animation;
}
} }
class AndroidGIFImageParser : GIFImageParser, IDisposable class AndroidGIFImageParser : GIFImageParser, IDisposable

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

@ -39,6 +39,6 @@ namespace Xamarin.Forms.Platform.Android
} }
bool IImageRendererController.IsDisposed => false; bool IImageRendererController.IsDisposed => false || !this.IsAlive();
} }
} }

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

@ -8,34 +8,28 @@ namespace Xamarin.Forms.Platform.Android
{ {
public class FormsTextView : TextView public class FormsTextView : TextView
{ {
bool _skip;
public FormsTextView(Context context) : base(context) public FormsTextView(Context context) : base(context)
{ {
} }
[Obsolete]
public FormsTextView(Context context, IAttributeSet attrs) : base(context, attrs) public FormsTextView(Context context, IAttributeSet attrs) : base(context, attrs)
{ {
} }
[Obsolete]
public FormsTextView(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle) public FormsTextView(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
{ {
} }
[Obsolete]
protected FormsTextView(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) protected FormsTextView(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{ {
} }
public override void Invalidate() [Obsolete]
{
if (!_skip)
base.Invalidate();
_skip = false;
}
public void SkipNextInvalidate() public void SkipNextInvalidate()
{ {
_skip = true;
} }
} }
} }

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

@ -125,7 +125,6 @@ namespace Xamarin.Forms.Platform.Android
} }
else else
{ {
_view.SkipNextInvalidate();
UpdateText(); UpdateText();
if (e.OldElement.LineBreakMode != e.NewElement.LineBreakMode) if (e.OldElement.LineBreakMode != e.NewElement.LineBreakMode)
UpdateLineBreakMode(); UpdateLineBreakMode();

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

@ -19,6 +19,8 @@ using Toolbar = Android.Support.V7.Widget.Toolbar;
using ADrawableCompat = Android.Support.V4.Graphics.Drawable.DrawableCompat; using ADrawableCompat = Android.Support.V4.Graphics.Drawable.DrawableCompat;
using ATextView = global::Android.Widget.TextView; using ATextView = global::Android.Widget.TextView;
using Android.Support.Design.Widget; using Android.Support.Design.Widget;
using AColor = Android.Graphics.Color;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Platform.Android namespace Xamarin.Forms.Platform.Android
{ {
@ -154,11 +156,8 @@ namespace Xamarin.Forms.Platform.Android
if (_backButtonBehavior != null) if (_backButtonBehavior != null)
_backButtonBehavior.PropertyChanged -= OnBackButtonBehaviorChanged; _backButtonBehavior.PropertyChanged -= OnBackButtonBehaviorChanged;
if(Page?.ToolbarItems?.Count > 0)
{ _toolbar.DisposeMenuItems(Page?.ToolbarItems, OnToolbarItemPropertyChanged);
foreach (var item in Page.ToolbarItems)
item.PropertyChanged -= OnToolbarItemPropertyChanged;
}
((IShellController)_shellContext?.Shell)?.RemoveFlyoutBehaviorObserver(this); ((IShellController)_shellContext?.Shell)?.RemoveFlyoutBehaviorObserver(this);
@ -492,37 +491,7 @@ namespace Xamarin.Forms.Platform.Android
protected virtual void UpdateToolbarItems(Toolbar toolbar, Page page) protected virtual void UpdateToolbarItems(Toolbar toolbar, Page page)
{ {
var menu = toolbar.Menu; var menu = toolbar.Menu;
menu.Clear(); toolbar.UpdateMenuItems(page.ToolbarItems, _shellContext.AndroidContext, TintColor, OnToolbarItemPropertyChanged);
foreach (var item in page.ToolbarItems)
{
item.PropertyChanged -= OnToolbarItemPropertyChanged;
item.PropertyChanged += OnToolbarItemPropertyChanged;
using (var title = new Java.Lang.String(item.Text))
{
var menuitem = menu.Add(title);
UpdateMenuItemIcon(_shellContext.AndroidContext, menuitem, item);
menuitem.SetTitleOrContentDescription(item);
menuitem.SetEnabled(item.IsEnabled);
if (item.Order != ToolbarItemOrder.Secondary)
menuitem.SetShowAsAction(ShowAsAction.Always);
menuitem.SetOnMenuItemClickListener(new GenericMenuClickListener(((IMenuItemController)item).Activate));
if (TintColor != Color.Default)
{
var view = toolbar.FindViewById(menuitem.ItemId);
if (view is ATextView textView)
textView.SetTextColor(TintColor.ToAndroid());
}
menuitem.Dispose();
}
}
SearchHandler = Shell.GetSearchHandler(page); SearchHandler = Shell.GetSearchHandler(page);
if (SearchHandler != null && SearchHandler.SearchBoxVisibility != SearchBoxVisibility.Hidden) if (SearchHandler != null && SearchHandler.SearchBoxVisibility != SearchBoxVisibility.Hidden)
@ -585,10 +554,7 @@ namespace Xamarin.Forms.Platform.Android
void OnToolbarItemPropertyChanged(object sender, PropertyChangedEventArgs e) void OnToolbarItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{ {
if (e.PropertyName == MenuItem.TextProperty.PropertyName) _toolbar.OnToolbarItemPropertyChanged(e, Page.ToolbarItems, _shellContext.AndroidContext, TintColor, OnToolbarItemPropertyChanged);
UpdateToolbarItems();
if (e.PropertyName == MenuItem.IconImageSourceProperty.PropertyName)
UpdateToolbarItems();
} }
void OnSearchViewAttachedToWindow(object sender, AView.ViewAttachedToWindowEventArgs e) void OnSearchViewAttachedToWindow(object sender, AView.ViewAttachedToWindowEventArgs e)

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

@ -143,10 +143,12 @@ namespace Xamarin.Forms.Platform.MacOS
AllowsUserCustomization = false, AllowsUserCustomization = false,
ShowsBaselineSeparator = true, ShowsBaselineSeparator = true,
SizeMode = NSToolbarSizeMode.Regular, SizeMode = NSToolbarSizeMode.Regular,
Delegate = this, Delegate = this
CenteredItemIdentifier = TitleGroupIdentifier
}; };
if (Forms.IsMojaveOrNewer)
toolbar.CenteredItemIdentifier = TitleGroupIdentifier;
return toolbar; return toolbar;
} }

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

@ -1,8 +1,34 @@
using EImage = ElmSharp.Image;
namespace Xamarin.Forms.Platform.Tizen namespace Xamarin.Forms.Platform.Tizen
{ {
internal static class ImageExtensions public static class ImageExtensions
{ {
internal static bool IsNullOrEmpty(this ImageSource imageSource) => public static void ApplyAspect(this EImage image, Aspect aspect)
{
Aspect _aspect = aspect;
switch (_aspect)
{
case Aspect.AspectFit:
image.IsFixedAspect = true;
image.CanFillOutside = false;
break;
case Aspect.AspectFill:
image.IsFixedAspect = true;
image.CanFillOutside = true;
break;
case Aspect.Fill:
image.IsFixedAspect = false;
image.CanFillOutside = false;
break;
default:
Log.Warn("Invalid Aspect value: {0}", _aspect);
break;
}
}
public static bool IsNullOrEmpty(this ImageSource imageSource) =>
imageSource == null || imageSource.IsEmpty; imageSource == null || imageSource.IsEmpty;
} }
} }

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

@ -1,91 +1,222 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Threading.Tasks;
using ElmSharp; using ElmSharp;
using Xamarin.Forms.Internals; using Xamarin.Forms.Internals;
using EColor = ElmSharp.Color;
namespace Xamarin.Forms.Platform.Tizen namespace Xamarin.Forms.Platform.Tizen
{ {
public class LightweightPlatform : BindableObject, ITizenPlatform public class LightweightPlatform : ITizenPlatform, INavigation, IDisposable
{ {
Page _page; NavigationModel _navModel = new NavigationModel();
EvasObject _rootView; Native.Canvas _viewStack;
bool _disposed; readonly PopupManager _popupManager;
bool _hasAlpha;
readonly EColor _defaultPlatformColor;
internal LightweightPlatform(EvasObject parent) public LightweightPlatform(EvasObject parent)
{ {
Forms.NativeParent = parent; Forms.NativeParent = parent;
_defaultPlatformColor = Device.Idiom == TargetIdiom.Phone ? EColor.White : EColor.Transparent;
_viewStack = new Native.Canvas(parent)
{
BackgroundColor = _defaultPlatformColor,
};
_viewStack.SetAlignment(-1, -1);
_viewStack.SetWeight(1.0, 1.0);
_viewStack.LayoutUpdated += OnLayout;
_viewStack.Show();
if (Forms.UseMessagingCenter)
{
_popupManager = new PopupManager(this);
}
} }
#pragma warning disable 0067
public event EventHandler<RootNativeViewChangedEventArgs> RootNativeViewChanged; public event EventHandler<RootNativeViewChangedEventArgs> RootNativeViewChanged;
#pragma warning restore 0067
public bool HasAlpha { get => false; set { } } public bool HasAlpha
{
get => _hasAlpha;
set
{
_hasAlpha = value;
_viewStack.BackgroundColor = _hasAlpha ? EColor.Transparent : _defaultPlatformColor;
}
}
IPageController CurrentPageController => _navModel.CurrentPage as IPageController;
IReadOnlyList<Page> INavigation.ModalStack => _navModel.Modals.ToList();
IReadOnlyList<Page> INavigation.NavigationStack => new List<Page>();
public void SetPage(Page page)
{
ResetChildren();
_navModel = new NavigationModel();
if (page == null)
return;
_navModel.Push(page, null);
#pragma warning disable CS0618 // Type or member is obsolete
page.Platform = this;
#pragma warning restore CS0618 // Type or member is obsolete
((Application)page.RealParent).NavigationProxy.Inner = this;
var renderer = Platform.CreateRenderer(page);
renderer.NativeView.Geometry = _viewStack.Geometry;
_viewStack.Children.Add(renderer.NativeView);
CurrentPageController?.SendAppearing();
}
public bool SendBackButtonPressed()
{
return _navModel?.CurrentPage?.SendBackButtonPressed() ?? false;
}
public EvasObject GetRootNativeView()
{
return _viewStack;
}
public bool PageIsChildOfPlatform(Page page)
{
var parent = page.AncestorToRoot();
return _navModel.Modals.FirstOrDefault() == page || _navModel.Roots.Contains(parent);
}
public void Dispose() public void Dispose()
{ {
Dispose(true); Dispose(true);
GC.SuppressFinalize(this);
}
public EvasObject GetRootNativeView() => _rootView;
public bool SendBackButtonPressed()
{
if (_page == null) return false;
return _page.SendBackButtonPressed();
}
public void SetPage(Page page)
{
if (_page == page) return;
if (_page != null)
{
var oldRenderer = Platform.GetRenderer(_page);
oldRenderer?.Dispose();
}
_page = page;
if (_page == null) return;
#pragma warning disable CS0618 // Type or member is obsolete
// The Platform property is no longer necessary, but we have to set it because some third-party
// library might still be retrieving it and using it
_page.Platform = this;
#pragma warning restore CS0618 // Type or member is obsolete
var renderer = Platform.CreateRenderer(_page);
_rootView = renderer.NativeView;
RootNativeViewChanged?.Invoke(this, new RootNativeViewChangedEventArgs(_rootView));
_rootView.Show();
Device.StartTimer(TimeSpan.Zero, () =>
{
_page?.SendAppearing();
return false;
});
}
protected override void OnBindingContextChanged()
{
BindableObject.SetInheritedBindingContext(_page, base.BindingContext);
base.OnBindingContextChanged();
} }
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (_disposed) return;
if (disposing) if (disposing)
{ {
SetPage(null); _popupManager?.Dispose();
_viewStack?.Unrealize();
} }
_disposed = true; }
Task<Page> INavigation.PopModalAsync()
{
return (this as INavigation).PopModalAsync(true);
}
Task<Page> INavigation.PopModalAsync(bool animated)
{
Page page = _navModel.PopModal();
(page as IPageController)?.SendDisappearing();
var renderer = Platform.GetRenderer(page);
_viewStack.Children.Remove(renderer.NativeView);
renderer.Dispose();
_viewStack.Children.LastOrDefault()?.Show();
CurrentPageController?.SendAppearing();
return Task.FromResult(page);
}
Task INavigation.PushModalAsync(Page modal)
{
return (this as INavigation).PushModalAsync(modal, true);
}
Task INavigation.PushModalAsync(Page page, bool animated)
{
var previousPage = CurrentPageController;
previousPage?.SendDisappearing();
_navModel.PushModal(page);
var lastTop = _viewStack.Children.LastOrDefault();
var renderer = Platform.GetOrCreateRenderer(page);
renderer.NativeView.Geometry = _viewStack.Geometry;
_viewStack.Children.Add(renderer.NativeView);
if (lastTop != null)
{
lastTop.Hide();
renderer.NativeView.StackAbove(lastTop);
}
// Verify that the modal is still on the stack
if (_navModel.CurrentPage == page)
CurrentPageController.SendAppearing();
return Task.CompletedTask;
}
void INavigation.InsertPageBefore(Page page, Page before)
{
throw new InvalidOperationException("InsertPageBefore is not supported globally on Tizen, please use a NavigationPage.");
}
Task<Page> INavigation.PopAsync()
{
return ((INavigation)this).PopAsync(true);
}
Task<Page> INavigation.PopAsync(bool animated)
{
throw new InvalidOperationException("PopAsync is not supported globally on Tizen, please use a NavigationPage.");
}
Task INavigation.PopToRootAsync()
{
return ((INavigation)this).PopToRootAsync(true);
}
Task INavigation.PopToRootAsync(bool animated)
{
throw new InvalidOperationException("PopToRootAsync is not supported globally on Tizen, please use a NavigationPage.");
}
Task INavigation.PushAsync(Page root)
{
return ((INavigation)this).PushAsync(root, true);
}
Task INavigation.PushAsync(Page root, bool animated)
{
throw new InvalidOperationException("PushAsync is not supported globally on Tizen, please use a NavigationPage.");
}
void INavigation.RemovePage(Page page)
{
throw new InvalidOperationException("RemovePage is not supported globally on Tizen, please use a NavigationPage.");
} }
SizeRequest IPlatform.GetNativeSize(VisualElement view, double widthConstraint, double heightConstraint) SizeRequest IPlatform.GetNativeSize(VisualElement view, double widthConstraint, double heightConstraint)
{ {
return Platform.GetNativeSize(view, widthConstraint, heightConstraint); return Platform.GetNativeSize(view, widthConstraint, heightConstraint);
} }
void OnLayout(object sender, Native.LayoutEventArgs e)
{
foreach (var child in _viewStack.Children)
{
child.Geometry = _viewStack.Geometry;
}
}
void ResetChildren()
{
var children = _viewStack.Children.ToList();
_viewStack.Children.Clear();
foreach (var child in children)
{
child.Unrealize();
}
}
} }
} }

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

@ -10,39 +10,12 @@ namespace Xamarin.Forms.Platform.Tizen.Native
/// </summary> /// </summary>
public class Image : EImage, IMeasurable public class Image : EImage, IMeasurable
{ {
Aspect _aspect;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.Native.Image"/> class. /// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.Native.Image"/> class.
/// </summary> /// </summary>
/// <param name="parent">The parent EvasObject.</param> /// <param name="parent">The parent EvasObject.</param>
public Image(EvasObject parent) : base(parent) public Image(EvasObject parent) : base(parent)
{ {
IsScaling = true;
CanScaleUp = true;
CanScaleDown = true;
ApplyAspect(Aspect.AspectFit);
}
/// <summary>
/// Gets or sets the image aspect ratio preserving option.
/// </summary>
/// <value>The aspect option.</value>
public Aspect Aspect
{
get
{
return _aspect;
}
set
{
if (_aspect != value)
{
ApplyAspect(value);
}
}
} }
/// <summary> /// <summary>
@ -67,6 +40,15 @@ namespace Xamarin.Forms.Platform.Tizen.Native
return isLoadComplate; return isLoadComplate;
} }
public bool LoadFromFile(string file)
{
if (!string.IsNullOrEmpty(file))
{
return Load(ResourcePath.GetPath(file));
}
return false;
}
/// <summary> /// <summary>
/// Implements the <see cref="Xamarin.Forms.Platform.Tizen.Native.IMeasurable"/> interface. /// Implements the <see cref="Xamarin.Forms.Platform.Tizen.Native.IMeasurable"/> interface.
/// </summary> /// </summary>
@ -75,7 +57,6 @@ namespace Xamarin.Forms.Platform.Tizen.Native
public ESize Measure(int availableWidth, int availableHeight) public ESize Measure(int availableWidth, int availableHeight)
{ {
var imageSize = ObjectSize; var imageSize = ObjectSize;
var size = new ESize() var size = new ESize()
{ {
Width = imageSize.Width, Width = imageSize.Width,
@ -96,36 +77,5 @@ namespace Xamarin.Forms.Platform.Tizen.Native
return size; return size;
} }
/// <summary>
/// Sets the <c>IsFixedAspect</c> and <c>CanFillOutside</c> properties according to the given <paramref name="aspect"/>.
/// </summary>
/// <param name="aspect">The aspect setting to be applied to the image.</param>
void ApplyAspect(Aspect aspect)
{
_aspect = aspect;
switch (_aspect)
{
case Aspect.AspectFit:
IsFixedAspect = true;
CanFillOutside = false;
break;
case Aspect.AspectFill:
IsFixedAspect = true;
CanFillOutside = true;
break;
case Aspect.Fill:
IsFixedAspect = false;
CanFillOutside = false;
break;
default:
Log.Warn("Invalid Aspect value: {0}", _aspect);
break;
}
}
} }
} }

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

@ -1,15 +1,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel; using System.ComponentModel;
using Xamarin.Forms.Internals; using System.Linq;
using Xamarin.Forms.PlatformConfiguration.TizenSpecific; using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using ElmSharp; using ElmSharp;
using EProgressBar = ElmSharp.ProgressBar; using Xamarin.Forms.Internals;
using EButton = ElmSharp.Button;
using EColor = ElmSharp.Color;
[assembly: InternalsVisibleTo("Xamarin.Forms.Material")] [assembly: InternalsVisibleTo("Xamarin.Forms.Material")]
@ -85,6 +81,7 @@ namespace Xamarin.Forms.Platform.Tizen
EvasObject GetRootNativeView(); EvasObject GetRootNativeView();
bool HasAlpha { get; set; } bool HasAlpha { get; set; }
event EventHandler<RootNativeViewChangedEventArgs> RootNativeViewChanged; event EventHandler<RootNativeViewChangedEventArgs> RootNativeViewChanged;
bool PageIsChildOfPlatform(Page page);
} }
public class RootNativeViewChangedEventArgs : EventArgs public class RootNativeViewChangedEventArgs : EventArgs
@ -97,9 +94,8 @@ namespace Xamarin.Forms.Platform.Tizen
{ {
NavigationModel _navModel = new NavigationModel(); NavigationModel _navModel = new NavigationModel();
bool _disposed; bool _disposed;
Native.Dialog _pageBusyDialog;
int _pageBusyCount;
readonly Naviframe _internalNaviframe; readonly Naviframe _internalNaviframe;
readonly PopupManager _popupManager;
readonly HashSet<EvasObject> _alerts = new HashSet<EvasObject>(); readonly HashSet<EvasObject> _alerts = new HashSet<EvasObject>();
@ -110,14 +106,6 @@ namespace Xamarin.Forms.Platform.Tizen
internal DefaultPlatform(EvasObject parent) internal DefaultPlatform(EvasObject parent)
{ {
Forms.NativeParent = parent; Forms.NativeParent = parent;
_pageBusyCount = 0;
if (Forms.UseMessagingCenter)
{
MessagingCenter.Subscribe<Page, bool>(this, Page.BusySetSignalName, BusySetSignalNameHandler);
MessagingCenter.Subscribe<Page, AlertArguments>(this, Page.AlertSignalName, AlertSignalNameHandler);
MessagingCenter.Subscribe<Page, ActionSheetArguments>(this, Page.ActionSheetSignalName, ActionSheetSignalNameHandler);
MessagingCenter.Subscribe<Page, PromptArguments>(this, Page.PromptSignalName, OnPromptRequested);
}
_internalNaviframe = new Naviframe(Forms.NativeParent) _internalNaviframe = new Naviframe(Forms.NativeParent)
{ {
@ -128,6 +116,11 @@ namespace Xamarin.Forms.Platform.Tizen
_internalNaviframe.SetWeight(1.0, 1.0); _internalNaviframe.SetWeight(1.0, 1.0);
_internalNaviframe.Show(); _internalNaviframe.Show();
_internalNaviframe.AnimationFinished += NaviAnimationFinished; _internalNaviframe.AnimationFinished += NaviAnimationFinished;
if (Forms.UseMessagingCenter)
{
_popupManager = new PopupManager(this);
}
} }
~DefaultPlatform() ~DefaultPlatform()
@ -224,18 +217,18 @@ namespace Xamarin.Forms.Platform.Tizen
return _internalNaviframe as EvasObject; return _internalNaviframe as EvasObject;
} }
public bool PageIsChildOfPlatform(Page page)
{
var parent = page.AncestorToRoot();
return Page == parent || _navModel.Roots.Contains(parent);
}
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (_disposed) return; if (_disposed) return;
if (disposing) if (disposing)
{ {
if (Forms.UseMessagingCenter) _popupManager?.Dispose();
{
MessagingCenter.Unsubscribe<Page, AlertArguments>(this, Page.AlertSignalName);
MessagingCenter.Unsubscribe<Page, bool>(this, Page.BusySetSignalName);
MessagingCenter.Unsubscribe<Page, ActionSheetArguments>(this, Page.ActionSheetSignalName);
MessagingCenter.Unsubscribe<Page, PromptArguments>(this, Page.PromptSignalName);
}
SetPage(null); SetPage(null);
_internalNaviframe.Unrealize(); _internalNaviframe.Unrealize();
} }
@ -405,263 +398,6 @@ namespace Xamarin.Forms.Platform.Tizen
tcs?.SetResult(true); tcs?.SetResult(true);
} }
void BusySetSignalNameHandler(Page sender, bool enabled)
{
// Verify that the page making the request is child of this platform
if (!PageIsChildOfPlatform(sender))
return;
if (null == _pageBusyDialog)
{
_pageBusyDialog = new Native.Dialog(Forms.NativeParent)
{
Orientation = PopupOrientation.Center,
BackgroundColor = EColor.Transparent
};
if (Device.Idiom == TargetIdiom.Phone)
{
_pageBusyDialog.SetPartColor("bg_title", EColor.Transparent);
_pageBusyDialog.SetPartColor("bg_content", EColor.Transparent);
}
else if (Device.Idiom == TargetIdiom.Watch)
{
_pageBusyDialog.Style = "circle";
}
var activity = new EProgressBar(_pageBusyDialog)
{
Style = "process_large",
IsPulseMode = true,
};
activity.PlayPulse();
activity.Show();
_pageBusyDialog.Content = activity;
}
_pageBusyCount = Math.Max(0, enabled ? _pageBusyCount + 1 : _pageBusyCount - 1);
if (_pageBusyCount > 0)
{
_pageBusyDialog.Show();
}
else
{
_pageBusyDialog.Dismiss();
_pageBusyDialog = null;
}
}
void AlertSignalNameHandler(Page sender, AlertArguments arguments)
{
// Verify that the page making the request is child of this platform
if (!PageIsChildOfPlatform(sender))
return;
Native.Dialog alert = Native.Dialog.CreateDialog(Forms.NativeParent, (arguments.Accept != null));
alert.Title = arguments.Title;
var message = arguments.Message.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace(Environment.NewLine, "<br>");
alert.Message = message;
EButton cancel = new EButton(alert) { Text = arguments.Cancel };
alert.NegativeButton = cancel;
cancel.Clicked += (s, evt) =>
{
arguments.SetResult(false);
alert.Dismiss();
};
if (arguments.Accept != null)
{
EButton ok = new EButton(alert) { Text = arguments.Accept };
alert.NeutralButton = ok;
ok.Clicked += (s, evt) =>
{
arguments.SetResult(true);
alert.Dismiss();
};
}
alert.BackButtonPressed += (s, evt) =>
{
arguments.SetResult(false);
alert.Dismiss();
};
alert.Show();
_alerts.Add(alert);
alert.Dismissed += (s, e) => _alerts.Remove(alert);
}
void ActionSheetSignalNameHandler(Page sender, ActionSheetArguments arguments)
{
// Verify that the page making the request is child of this platform
if (!PageIsChildOfPlatform(sender))
return;
Native.Dialog alert = Native.Dialog.CreateDialog(Forms.NativeParent);
alert.Title = arguments.Title;
Box box = new Box(alert);
if (null != arguments.Destruction)
{
Native.Button destruction = new Native.Button(alert)
{
Text = arguments.Destruction,
Style = ButtonStyle.Text,
TextColor = EColor.Red,
AlignmentX = -1
};
destruction.Clicked += (s, evt) =>
{
arguments.SetResult(arguments.Destruction);
alert.Dismiss();
};
destruction.Show();
box.PackEnd(destruction);
}
foreach (string buttonName in arguments.Buttons)
{
Native.Button button = new Native.Button(alert)
{
Text = buttonName,
Style = ButtonStyle.Text,
AlignmentX = -1
};
button.Clicked += (s, evt) =>
{
arguments.SetResult(buttonName);
alert.Dismiss();
};
button.Show();
box.PackEnd(button);
}
box.Show();
alert.Content = box;
if (null != arguments.Cancel)
{
EButton cancel = new EButton(Forms.NativeParent) { Text = arguments.Cancel };
alert.NegativeButton = cancel;
cancel.Clicked += (s, evt) =>
{
alert.Dismiss();
};
}
alert.BackButtonPressed += (s, evt) =>
{
alert.Dismiss();
};
alert.Show();
_alerts.Add(alert);
alert.Dismissed += (s, e) => _alerts.Remove(alert);
}
void OnPromptRequested(Page sender, PromptArguments args)
{
// Verify that the page making the request is child of this platform
if (!PageIsChildOfPlatform(sender))
return;
var prompt = Native.Dialog.CreateDialog(Forms.NativeParent, (args.Accept != null));
prompt.Title = args.Title;
var entry = new Entry
{
MinimumWidthRequest = 200,
HorizontalOptions = LayoutOptions.FillAndExpand,
BackgroundColor = Color.FromRgb(250, 250, 250),
TextColor = Color.Black,
Keyboard = args.Keyboard,
};
if (!string.IsNullOrEmpty(args.Placeholder))
{
entry.Placeholder = args.Placeholder;
}
if (args.MaxLength > 0)
{
entry.MaxLength = args.MaxLength;
}
var layout = new StackLayout
{
Spacing = 10,
Children =
{
new Label
{
LineBreakMode = LineBreakMode.CharacterWrap,
TextColor = Device.Idiom == TargetIdiom.Watch ? Color.White : Color.Accent,
Text = args.Message,
HorizontalOptions = LayoutOptions.FillAndExpand,
HorizontalTextAlignment = TextAlignment.Center,
FontSize = Device.GetNamedSize(NamedSize.Subtitle, typeof(Label)),
},
entry,
}
};
layout.Parent = sender;
var layoutrenderer = Platform.GetOrCreateRenderer(layout);
var request = layout.Measure(Device.Idiom == TargetIdiom.Watch ? Page.Width * 0.7 : Page.Width, Page.Height);
(layoutrenderer as LayoutRenderer).RegisterOnLayoutUpdated();
layoutrenderer.NativeView.MinimumHeight = Forms.ConvertToScaledPixel(request.Request.Height);
layoutrenderer.NativeView.MinimumWidth = Forms.ConvertToScaledPixel(request.Request.Width);
prompt.Content = layoutrenderer.NativeView;
var cancel = new EButton(prompt) { Text = args.Cancel };
prompt.NegativeButton = cancel;
cancel.Clicked += (s, evt) =>
{
args.SetResult(null);
prompt.Dismiss();
};
if (args.Accept != null)
{
var ok = new EButton(prompt) { Text = args.Accept };
prompt.NeutralButton = ok;
ok.Clicked += (s, evt) =>
{
args.SetResult(entry.Text);
prompt.Dismiss();
};
}
entry.Completed += (s, e) =>
{
args.SetResult(entry.Text);
prompt.Dismiss();
};
prompt.BackButtonPressed += (s, evt) =>
{
args.SetResult(null);
prompt.Dismiss();
};
prompt.Show();
_alerts.Add(prompt);
prompt.Dismissed += (s, e) => _alerts.Remove(prompt);
}
bool PageIsChildOfPlatform(Page page)
{
var parent = page.AncestorToRoot();
return Page == parent || _navModel.Roots.Contains(parent);
}
SizeRequest IPlatform.GetNativeSize(VisualElement view, double widthConstraint, double heightConstraint) SizeRequest IPlatform.GetNativeSize(VisualElement view, double widthConstraint, double heightConstraint)
{ {
return Platform.GetNativeSize(view, widthConstraint, heightConstraint); return Platform.GetNativeSize(view, widthConstraint, heightConstraint);

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

@ -0,0 +1,295 @@
using System;
using System.Collections.Generic;
using ElmSharp;
using Xamarin.Forms.Internals;
using Xamarin.Forms.PlatformConfiguration.TizenSpecific;
using EButton = ElmSharp.Button;
using EColor = ElmSharp.Color;
using EProgressBar = ElmSharp.ProgressBar;
namespace Xamarin.Forms.Platform.Tizen
{
public class PopupManager : IDisposable
{
ITizenPlatform _platform;
Native.Dialog _pageBusyDialog;
int _pageBusyCount;
readonly HashSet<EvasObject> _alerts = new HashSet<EvasObject>();
public PopupManager(ITizenPlatform platform)
{
_platform = platform;
MessagingCenter.Subscribe<Page, bool>(this, Page.BusySetSignalName, OnBusySetRequest);
MessagingCenter.Subscribe<Page, AlertArguments>(this, Page.AlertSignalName, OnAlertRequest);
MessagingCenter.Subscribe<Page, ActionSheetArguments>(this, Page.ActionSheetSignalName, OnActionSheetRequest);
MessagingCenter.Subscribe<Page, PromptArguments>(this, Page.PromptSignalName, OnPromptRequested);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
MessagingCenter.Unsubscribe<Page, AlertArguments>(this, Page.AlertSignalName);
MessagingCenter.Unsubscribe<Page, bool>(this, Page.BusySetSignalName);
MessagingCenter.Unsubscribe<Page, ActionSheetArguments>(this, Page.ActionSheetSignalName);
MessagingCenter.Unsubscribe<Page, PromptArguments>(this, Page.PromptSignalName);
}
}
void OnBusySetRequest(Page sender, bool enabled)
{
// Verify that the page making the request is child of this platform
if (!_platform.PageIsChildOfPlatform(sender))
return;
if (null == _pageBusyDialog)
{
_pageBusyDialog = new Native.Dialog(Forms.NativeParent)
{
Orientation = PopupOrientation.Center,
BackgroundColor = EColor.Transparent
};
if (Device.Idiom == TargetIdiom.Phone)
{
_pageBusyDialog.SetPartColor("bg_title", EColor.Transparent);
_pageBusyDialog.SetPartColor("bg_content", EColor.Transparent);
}
else if (Device.Idiom == TargetIdiom.Watch)
{
_pageBusyDialog.Style = "circle";
}
var activity = new EProgressBar(_pageBusyDialog)
{
Style = "process_large",
IsPulseMode = true,
};
activity.PlayPulse();
activity.Show();
_pageBusyDialog.Content = activity;
}
_pageBusyCount = Math.Max(0, enabled ? _pageBusyCount + 1 : _pageBusyCount - 1);
if (_pageBusyCount > 0)
{
_pageBusyDialog.Show();
}
else
{
_pageBusyDialog.Dismiss();
_pageBusyDialog = null;
}
}
void OnAlertRequest(Page sender, AlertArguments arguments)
{
// Verify that the page making the request is child of this platform
if (!_platform.PageIsChildOfPlatform(sender))
return;
var alert = Native.Dialog.CreateDialog(Forms.NativeParent, (arguments.Accept != null));
alert.Title = arguments.Title;
var message = arguments.Message.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace(Environment.NewLine, "<br>");
alert.Message = message;
var cancel = new EButton(alert) { Text = arguments.Cancel };
alert.NegativeButton = cancel;
cancel.Clicked += (s, evt) =>
{
arguments.SetResult(false);
alert.Dismiss();
};
if (arguments.Accept != null)
{
var ok = new EButton(alert) { Text = arguments.Accept };
alert.NeutralButton = ok;
ok.Clicked += (s, evt) =>
{
arguments.SetResult(true);
alert.Dismiss();
};
}
alert.BackButtonPressed += (s, evt) =>
{
arguments.SetResult(false);
alert.Dismiss();
};
alert.Show();
_alerts.Add(alert);
alert.Dismissed += (s, e) => _alerts.Remove(alert);
}
void OnActionSheetRequest(Page sender, ActionSheetArguments arguments)
{
// Verify that the page making the request is child of this platform
if (!_platform.PageIsChildOfPlatform(sender))
return;
var alert = Native.Dialog.CreateDialog(Forms.NativeParent);
alert.Title = arguments.Title;
var box = new Box(alert);
if (null != arguments.Destruction)
{
var destruction = new Native.Button(alert)
{
Text = arguments.Destruction,
Style = ButtonStyle.Text,
TextColor = EColor.Red,
AlignmentX = -1
};
destruction.Clicked += (s, evt) =>
{
arguments.SetResult(arguments.Destruction);
alert.Dismiss();
};
destruction.Show();
box.PackEnd(destruction);
}
foreach (string buttonName in arguments.Buttons)
{
var button = new Native.Button(alert)
{
Text = buttonName,
Style = ButtonStyle.Text,
AlignmentX = -1
};
button.Clicked += (s, evt) =>
{
arguments.SetResult(buttonName);
alert.Dismiss();
};
button.Show();
box.PackEnd(button);
}
box.Show();
alert.Content = box;
if (null != arguments.Cancel)
{
var cancel = new EButton(Forms.NativeParent) { Text = arguments.Cancel };
alert.NegativeButton = cancel;
cancel.Clicked += (s, evt) =>
{
alert.Dismiss();
};
}
alert.BackButtonPressed += (s, evt) =>
{
alert.Dismiss();
};
alert.Show();
_alerts.Add(alert);
alert.Dismissed += (s, e) => _alerts.Remove(alert);
}
void OnPromptRequested(Page sender, PromptArguments args)
{
// Verify that the page making the request is child of this platform
if (!_platform.PageIsChildOfPlatform(sender))
return;
var prompt = Native.Dialog.CreateDialog(Forms.NativeParent, (args.Accept != null));
prompt.Title = args.Title;
var entry = new Entry
{
MinimumWidthRequest = 200,
HorizontalOptions = LayoutOptions.FillAndExpand,
BackgroundColor = Color.FromRgb(250, 250, 250),
TextColor = Color.Black,
Keyboard = args.Keyboard,
};
if (!string.IsNullOrEmpty(args.Placeholder))
{
entry.Placeholder = args.Placeholder;
}
if (args.MaxLength > 0)
{
entry.MaxLength = args.MaxLength;
}
var layout = new StackLayout
{
Spacing = 10,
Children =
{
new Label
{
LineBreakMode = LineBreakMode.CharacterWrap,
TextColor = Device.Idiom == TargetIdiom.Watch ? Color.White : Color.Accent,
Text = args.Message,
HorizontalOptions = LayoutOptions.FillAndExpand,
HorizontalTextAlignment = TextAlignment.Center,
FontSize = Device.GetNamedSize(NamedSize.Subtitle, typeof(Label)),
},
entry,
}
};
layout.Parent = sender;
var layoutrenderer = Platform.GetOrCreateRenderer(layout);
var request = layout.Measure(Device.Idiom == TargetIdiom.Watch ? sender.Width * 0.7 : sender.Width, sender.Height);
(layoutrenderer as LayoutRenderer).RegisterOnLayoutUpdated();
layoutrenderer.NativeView.MinimumHeight = Forms.ConvertToScaledPixel(request.Request.Height);
layoutrenderer.NativeView.MinimumWidth = Forms.ConvertToScaledPixel(request.Request.Width);
prompt.Content = layoutrenderer.NativeView;
var cancel = new EButton(prompt) { Text = args.Cancel };
prompt.NegativeButton = cancel;
cancel.Clicked += (s, evt) =>
{
args.SetResult(null);
prompt.Dismiss();
};
if (args.Accept != null)
{
var ok = new EButton(prompt) { Text = args.Accept };
prompt.NeutralButton = ok;
ok.Clicked += (s, evt) =>
{
args.SetResult(entry.Text);
prompt.Dismiss();
};
}
entry.Completed += (s, e) =>
{
args.SetResult(entry.Text);
prompt.Dismiss();
};
prompt.BackButtonPressed += (s, evt) =>
{
prompt.Dismiss();
};
prompt.Show();
_alerts.Add(prompt);
prompt.Dismissed += (s, e) => _alerts.Remove(prompt);
}
}
}

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

@ -177,7 +177,7 @@ namespace Xamarin.Forms.Platform.Tizen
void UpdateAspect() void UpdateAspect()
{ {
_image.Aspect = Element.Aspect; _image.ApplyAspect(Element.Aspect);
} }
} }
} }

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

@ -8,52 +8,41 @@ namespace Xamarin.Forms.Platform.Tizen
{ {
public class ImageRenderer : ViewRenderer<Image, Native.Image> public class ImageRenderer : ViewRenderer<Image, Native.Image>
{ {
public ImageRenderer()
{
RegisterPropertyHandler(Image.SourceProperty, UpdateSource);
RegisterPropertyHandler(Image.AspectProperty, UpdateAspect);
RegisterPropertyHandler(Image.IsOpaqueProperty, UpdateIsOpaque);
RegisterPropertyHandler(Image.IsAnimationPlayingProperty, UpdateIsAnimationPlaying);
RegisterPropertyHandler(Specific.BlendColorProperty, UpdateBlendColor);
RegisterPropertyHandler(Specific.FileProperty, UpdateFile);
}
protected override void OnElementChanged(ElementChangedEventArgs<Image> e) protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
{ {
if (Control == null) if (Control == null)
{ {
var image = new Native.Image(Forms.NativeParent); SetNativeControl(new Native.Image(Forms.NativeParent));
SetNativeControl(image);
} }
UpdateAll();
base.OnElementChanged(e); base.OnElementChanged(e);
} }
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) async void UpdateSource(bool initialize)
{ {
base.OnElementPropertyChanged(sender, e); if (initialize && Element.Source == default(ImageSource))
if (e.PropertyName == Image.SourceProperty.PropertyName) return;
{
UpdateSource();
}
else if (e.PropertyName == Image.AspectProperty.PropertyName)
{
UpdateAspect();
}
else if (e.PropertyName == Image.IsOpaqueProperty.PropertyName)
{
UpdateIsOpaque();
}
else if (e.PropertyName == Specific.BlendColorProperty.PropertyName)
{
UpdateBlendColor();
}
}
async void UpdateSource()
{
ImageSource source = Element.Source; ImageSource source = Element.Source;
((IImageController)Element).SetIsLoading(true); ((IImageController)Element).SetIsLoading(true);
if (Control != null) if (Control != null)
{ {
bool success = await Control.LoadFromImageSourceAsync(source); bool success = await Control.LoadFromImageSourceAsync(source);
if (!IsDisposed && success) if (!IsDisposed && success)
{ {
((IVisualElementController)Element).NativeSizeChanged(); ((IVisualElementController)Element).NativeSizeChanged();
UpdateAfterLoading(); UpdateAfterLoading(initialize);
} }
} }
@ -61,31 +50,61 @@ namespace Xamarin.Forms.Platform.Tizen
((IImageController)Element).SetIsLoading(false); ((IImageController)Element).SetIsLoading(false);
} }
protected virtual void UpdateAfterLoading() void UpdateFile(bool initialize)
{ {
UpdateIsOpaque(); if (initialize && Specific.GetFile(Element) == default || Element.Source != default(ImageSource))
UpdateBlendColor(); return;
if (Control != null)
{
bool success = Control.LoadFromFile(Specific.GetFile(Element));
if (!IsDisposed && success)
{
((IVisualElementController)Element).NativeSizeChanged();
UpdateAfterLoading(initialize);
}
}
} }
void UpdateAspect() protected virtual void UpdateAfterLoading(bool initialize)
{ {
Control.Aspect = Element.Aspect; UpdateIsOpaque(initialize);
UpdateBlendColor(initialize);
UpdateIsAnimationPlaying(initialize);
} }
void UpdateIsOpaque() void UpdateAspect(bool initialize)
{ {
if (initialize && Element.Aspect == Aspect.AspectFit)
return;
Control.ApplyAspect(Element.Aspect);
}
void UpdateIsOpaque(bool initialize)
{
if (initialize && !Element.IsOpaque)
return;
Control.IsOpaque = Element.IsOpaque; Control.IsOpaque = Element.IsOpaque;
} }
void UpdateBlendColor() void UpdateIsAnimationPlaying(bool initialize)
{ {
Control.Color = Specific.GetBlendColor(Element).ToNative(); if (initialize && !Element.IsAnimationPlaying)
return;
Control.IsAnimated = Element.IsAnimationPlaying;
Control.IsAnimationPlaying = Element.IsAnimationPlaying;
} }
void UpdateAll() void UpdateBlendColor(bool initialize)
{ {
UpdateSource(); if (initialize && Specific.GetBlendColor(Element).IsDefault)
UpdateAspect(); return;
Control.Color = Specific.GetBlendColor(Element).ToNative();
} }
} }

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

@ -1,18 +1,20 @@
using System; using System;
using System.Reflection; using System.Reflection;
using ElmSharp; using ElmSharp;
using EColor = ElmSharp.Color;
using Xamarin.Forms.Platform.Tizen.Native; using Xamarin.Forms.Platform.Tizen.Native;
using EColor = ElmSharp.Color;
using EButton = ElmSharp.Button;
using EImage = ElmSharp.Image;
namespace Xamarin.Forms.Platform.Tizen namespace Xamarin.Forms.Platform.Tizen
{ {
public class ShellNavBar : Native.Box public class ShellNavBar : Native.Box
{ {
Native.Image _menu = null; EImage _menu = null;
EButton _menuButton = null;
Native.Label _title = null; Native.Label _title = null;
Native.SearchBar _nativeSearchHandler = null; Native.SearchBar _nativeSearchHandler = null;
EvasObject _nativeTitleView = null; EvasObject _nativeTitleView = null;
ShellSectionNavigation _shellSectionNavigation = null;
SearchHandler _searchHandler = null; SearchHandler _searchHandler = null;
View _titleView = null; View _titleView = null;
@ -29,15 +31,18 @@ namespace Xamarin.Forms.Platform.Tizen
bool _hasBackButton = false; bool _hasBackButton = false;
public ShellNavBar(IFlyoutController flyoutController, ShellSectionNavigation shellSectionNavigation) : base(Forms.NativeParent) public ShellNavBar(IFlyoutController flyoutController) : base(Forms.NativeParent)
{ {
_flyoutController = flyoutController; _flyoutController = flyoutController;
_shellSectionNavigation = shellSectionNavigation;
_menu = new Native.Image(Forms.NativeParent); _menuButton = new EButton(Forms.NativeParent);
_menu.Clicked += OnMenuClicked; _menuButton.Clicked += OnMenuClicked;
_menu = new EImage(Forms.NativeParent);
UpdateMenuIcon(); UpdateMenuIcon();
_menu.Show(); _menu.Show();
_menuButton.Show();
_menuButton.SetPartContent("icon", _menu);
_title = new Native.Label(Forms.NativeParent) _title = new Native.Label(Forms.NativeParent)
{ {
@ -49,7 +54,8 @@ namespace Xamarin.Forms.Platform.Tizen
_title.Show(); _title.Show();
BackgroundColor = _backgroudColor; BackgroundColor = _backgroudColor;
PackEnd(_menu); _menuButton.BackgroundColor = _backgroudColor;
PackEnd(_menuButton);
PackEnd(_title); PackEnd(_title);
LayoutUpdated += OnLayoutUpdated; LayoutUpdated += OnLayoutUpdated;
} }
@ -123,6 +129,7 @@ namespace Xamarin.Forms.Platform.Tizen
set set
{ {
_backgroudColor = value; _backgroudColor = value;
_menuButton.BackgroundColor = _backgroudColor;
base.BackgroundColor = _backgroudColor; base.BackgroundColor = _backgroudColor;
} }
} }
@ -136,7 +143,7 @@ namespace Xamarin.Forms.Platform.Tizen
set set
{ {
_foregroudColor = value; _foregroudColor = value;
_menu.Color = value; _menuButton.Color = value;
} }
} }
@ -164,11 +171,11 @@ namespace Xamarin.Forms.Platform.Tizen
} }
} }
async void UpdateMenuIcon() void UpdateMenuIcon()
{ {
string file = _hasBackButton ? _backIcon : _menuIcon; string file = _hasBackButton ? _backIcon : _menuIcon;
ImageSource source = ImageSource.FromResource(file, typeof(ShellNavBar).GetTypeInfo().Assembly); var path = Assembly.GetExecutingAssembly().GetManifestResourceStream(file);
bool ret = await _menu.LoadFromImageSourceAsync(source); _menu.Load(path);
} }
void OnMenuClicked(object sender, EventArgs e) void OnMenuClicked(object sender, EventArgs e)
@ -180,7 +187,7 @@ namespace Xamarin.Forms.Platform.Tizen
} }
else if (_hasBackButton) else if (_hasBackButton)
{ {
_shellSectionNavigation.PopRequest(this, new Internals.NavigationRequestedEventArgs(_page, false)); Shell.Current.CurrentItem.Navigation.PopAsync();
} }
else else
{ {
@ -258,8 +265,8 @@ namespace Xamarin.Forms.Platform.Tizen
int titleLeftMargin = 40; int titleLeftMargin = 40;
int titleViewTopMargin = 40; int titleViewTopMargin = 40;
_menu.Move(e.Geometry.X + menuMargin, e.Geometry.Y + (e.Geometry.Height - menuSize) / 2); _menuButton.Move(e.Geometry.X + menuMargin, e.Geometry.Y + (e.Geometry.Height - menuSize) / 2);
_menu.Resize(menuSize, menuSize); _menuButton.Resize(menuSize, menuSize);
if (_searchHandler != null) if (_searchHandler != null)
{ {

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

@ -30,7 +30,7 @@ namespace Xamarin.Forms.Platform.Tizen
_section.PropertyChanged += OnSectionPropertyChanged; _section.PropertyChanged += OnSectionPropertyChanged;
_rootPage = ((IShellContentController)_section.CurrentItem).GetOrCreateContent(); _rootPage = ((IShellContentController)_section.CurrentItem).GetOrCreateContent();
_navBar = new ShellNavBar(flyoutController, this); _navBar = new ShellNavBar(flyoutController);
_navBar.Show(); _navBar.Show();
var renderer = CreateShellSection(section); var renderer = CreateShellSection(section);

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

@ -431,7 +431,7 @@ namespace Xamarin.Forms.Platform.UWP
var toolBarForegroundBinder = GetToolbarProvider() as IToolBarForegroundBinder; var toolBarForegroundBinder = GetToolbarProvider() as IToolBarForegroundBinder;
foreach (ToolbarItem item in _toolbarTracker.ToolbarItems.OrderBy(ti => ti.Priority)) foreach (ToolbarItem item in _toolbarTracker.ToolbarItems)
{ {
toolBarForegroundBinder?.BindForegroundColor(commandBar); toolBarForegroundBinder?.BindForegroundColor(commandBar);

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

@ -93,6 +93,7 @@ namespace Xamarin.Forms.Platform.WPF
{ {
int lengthDifference = base.Text.Length - Text.Length; int lengthDifference = base.Text.Length - Text.Length;
var savedSelectionStart = SelectionStart;
string updatedRealText = DetermineTextFromPassword(Text, SelectionStart, base.Text); string updatedRealText = DetermineTextFromPassword(Text, SelectionStart, base.Text);
if (Text == updatedRealText) if (Text == updatedRealText)
@ -101,7 +102,9 @@ namespace Xamarin.Forms.Platform.WPF
return; return;
} }
_internalChangeFlag = true;
Text = updatedRealText; Text = updatedRealText;
_internalChangeFlag = false;
// Cancel any pending delayed obfuscation // Cancel any pending delayed obfuscation
_cts?.Cancel(); _cts?.Cancel();
@ -118,10 +121,10 @@ namespace Xamarin.Forms.Platform.WPF
else else
{ {
// Only one character was added; we need to leave it visible for a brief time period // Only one character was added; we need to leave it visible for a brief time period
// Obfuscate all but the last character for now // Obfuscate all but the character added for now
newText = Obfuscate(Text, true); newText = Obfuscate(Text, savedSelectionStart - 1);
// Leave the last character visible until a new character is added // Leave the added character visible until a new character is added
// or sufficient time has passed // or sufficient time has passed
if (_cts == null) if (_cts == null)
{ {
@ -134,19 +137,20 @@ namespace Xamarin.Forms.Platform.WPF
_cts.Token.ThrowIfCancellationRequested(); _cts.Token.ThrowIfCancellationRequested();
await Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => await Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{ {
var ss = SelectionStart;
var sl = SelectionLength;
base.Text = Obfuscate(Text); base.Text = Obfuscate(Text);
SelectionStart = base.Text.Length; SelectionStart = ss;
SelectionLength = sl;
})); }));
}, _cts.Token); }, _cts.Token);
} }
if (base.Text == newText) if (base.Text != newText)
{ {
return;
}
base.Text = newText; base.Text = newText;
SelectionStart = base.Text.Length; }
SelectionStart = savedSelectionStart;
} }
static string DetermineTextFromPassword(string realText, int start, string passwordText) static string DetermineTextFromPassword(string realText, int start, string passwordText)
@ -164,14 +168,19 @@ namespace Xamarin.Forms.Platform.WPF
return sb.ToString(); return sb.ToString();
} }
string Obfuscate(string text, bool leaveLastVisible = false) string Obfuscate(string text, int visibleSymbolIndex = -1)
{ {
if (!leaveLastVisible) if (visibleSymbolIndex == -1)
return new string(ObfuscationCharacter, text?.Length ?? 0); return new string(ObfuscationCharacter, text?.Length ?? 0);
return text == null || text.Length == 1 if (text == null || text.Length == 1)
? text return text;
: new string(ObfuscationCharacter, text.Length - 1) + text.Substring(text.Length - 1, 1); var prefix = visibleSymbolIndex > 0 ? new string(ObfuscationCharacter, visibleSymbolIndex) : string.Empty;
var suffix = visibleSymbolIndex == text.Length - 1
? string.Empty
: new string(ObfuscationCharacter, text.Length - visibleSymbolIndex - 1);
return prefix + text.Substring(visibleSymbolIndex, 1) + suffix;
} }
static void OnIsPasswordChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) static void OnIsPasswordChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
@ -234,7 +243,11 @@ namespace Xamarin.Forms.Platform.WPF
base.OnKeyDown(e); base.OnKeyDown(e);
if (_cachedSelectionLength > 0 && !ctrlDown) if (_cachedSelectionLength > 0 && !ctrlDown)
{
var savedSelectionStart = SelectionStart;
Text = Text.Remove(SelectionStart, _cachedSelectionLength); Text = Text.Remove(SelectionStart, _cachedSelectionLength);
SelectionStart = savedSelectionStart;
}
} }
} }
else else
@ -245,17 +258,7 @@ namespace Xamarin.Forms.Platform.WPF
{ {
if (IsPassword) if (IsPassword)
{ {
string updatedRealText = DetermineTextFromPassword(Text, SelectionStart, base.Text); DelayObfuscation();
string updatedText = Obfuscate(updatedRealText);
var savedSelectionStart = SelectionStart;
if (Text != updatedRealText)
Text = updatedRealText;
if (base.Text != updatedText)
base.Text = updatedText;
SelectionStart = savedSelectionStart;
} }
else if (base.Text != Text) else if (base.Text != Text)
{ {
@ -272,11 +275,11 @@ namespace Xamarin.Forms.Platform.WPF
{ {
if (_internalChangeFlag) if (_internalChangeFlag)
return; return;
var savedSelectionStart = SelectionStart;
base.Text = IsPassword ? Obfuscate(Text) : Text; base.Text = IsPassword ? Obfuscate(Text) : Text;
DisabledText = base.Text; DisabledText = base.Text;
var len = base.Text.Length;
SelectionStart = base.Text.Length; SelectionStart = savedSelectionStart > len ? len : savedSelectionStart;
} }
static void TextPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) static void TextPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)

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

@ -108,13 +108,17 @@ namespace Xamarin.Forms.Platform.WPF
((IElementController)Element).SetValueFromRenderer(Entry.TextProperty, Control.Text); ((IElementController)Element).SetValueFromRenderer(Entry.TextProperty, Control.Text);
// If an Entry.TextChanged handler modified the value of the Entry's text, the values could now be // If an Entry.TextChanged handler modified the value of the Entry's text, the values could now be
// out-of-sync; re-sync them and force the TextBox cursor to the end of the text // out-of-sync; re-sync them and fix TextBox cursor position
string entryText = Element.Text; string entryText = Element.Text;
if (Control.Text != entryText) if (Control.Text != entryText)
{ {
Control.Text = entryText; Control.Text = entryText;
if (Control.Text != null) if (Control.Text != null)
Control.SelectionStart = Control.Text.Length; {
var savedSelectionStart = Control.SelectionStart;
var len = Control.Text.Length;
Control.SelectionStart = savedSelectionStart > len ? len : savedSelectionStart;
}
} }
_ignoreTextChange = false; _ignoreTextChange = false;

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

@ -38,9 +38,7 @@ namespace Xamarin.Forms
static bool? s_isiOS11OrNewer; static bool? s_isiOS11OrNewer;
static bool? s_isiOS13OrNewer; static bool? s_isiOS13OrNewer;
static bool? s_respondsTosetNeedsUpdateOfHomeIndicatorAutoHidden; static bool? s_respondsTosetNeedsUpdateOfHomeIndicatorAutoHidden;
#endif
#if __MOBILE__
internal static bool IsiOS9OrNewer internal static bool IsiOS9OrNewer
{ {
get get
@ -91,6 +89,19 @@ namespace Xamarin.Forms
return s_respondsTosetNeedsUpdateOfHomeIndicatorAutoHidden.Value; return s_respondsTosetNeedsUpdateOfHomeIndicatorAutoHidden.Value;
} }
} }
#else
static bool? s_isMojaveOrNewer;
internal static bool IsMojaveOrNewer
{
get
{
if (!s_isMojaveOrNewer.HasValue)
s_isMojaveOrNewer = NSProcessInfo.ProcessInfo.IsOperatingSystemAtLeastVersion(new NSOperatingSystemVersion(10, 14, 0));
return s_isMojaveOrNewer.Value;
}
}
#endif #endif
static IReadOnlyList<string> s_flags; static IReadOnlyList<string> s_flags;

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

@ -1211,7 +1211,8 @@ namespace Xamarin.Forms.Platform.iOS
List<UIBarButtonItem> primaries = null; List<UIBarButtonItem> primaries = null;
List<UIBarButtonItem> secondaries = null; List<UIBarButtonItem> secondaries = null;
foreach (var item in _tracker.ToolbarItems) var toolbarItems = _tracker.ToolbarItems;
foreach (var item in toolbarItems)
{ {
if (item.Order == ToolbarItemOrder.Secondary) if (item.Order == ToolbarItemOrder.Secondary)
(secondaries = secondaries ?? new List<UIBarButtonItem>()).Add(item.ToUIBarButtonItem(true)); (secondaries = secondaries ?? new List<UIBarButtonItem>()).Add(item.ToUIBarButtonItem(true));

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

@ -197,17 +197,19 @@ namespace Xamarin.Forms.Platform.iOS
NavigationItem.RightBarButtonItems[i].Dispose(); NavigationItem.RightBarButtonItems[i].Dispose();
} }
List<UIBarButtonItem> items = new List<UIBarButtonItem>(); List<UIBarButtonItem> primaries = null;
if (Page != null) if (Page.ToolbarItems.Count > 0)
{ {
foreach (var item in Page.ToolbarItems) foreach (var item in System.Linq.Enumerable.OrderBy(Page.ToolbarItems, x => x.Priority))
{ {
items.Add(item.ToUIBarButtonItem(false, true)); (primaries = primaries ?? new List<UIBarButtonItem>()).Add(item.ToUIBarButtonItem(false, true));
}
} }
items.Reverse(); if (primaries != null)
NavigationItem.SetRightBarButtonItems(items.ToArray(), false); primaries.Reverse();
}
NavigationItem.SetRightBarButtonItems(primaries == null ? new UIBarButtonItem[0] : primaries.ToArray(), false);
var behavior = BackButtonBehavior; var behavior = BackButtonBehavior;

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

@ -62,7 +62,6 @@ namespace Xamarin.Forms.Platform.iOS
Page _displayedPage; Page _displayedPage;
bool _disposed; bool _disposed;
bool _firstLayoutCompleted; bool _firstLayoutCompleted;
bool _ignorePop;
TaskCompletionSource<bool> _popCompletionTask; TaskCompletionSource<bool> _popCompletionTask;
IShellSectionRootRenderer _renderer; IShellSectionRootRenderer _renderer;
ShellSection _shellSection; ShellSection _shellSection;
@ -73,17 +72,6 @@ namespace Xamarin.Forms.Platform.iOS
_context = context; _context = context;
} }
public override UIViewController PopViewController(bool animated)
{
if (!_ignorePop)
{
_popCompletionTask = new TaskCompletionSource<bool>();
SendPoppedOnCompletion(_popCompletionTask.Task);
}
return base.PopViewController(animated);
}
[Export("navigationBar:shouldPopItem:")] [Export("navigationBar:shouldPopItem:")]
public bool ShouldPopItem(UINavigationBar navigationBar, UINavigationItem item) public bool ShouldPopItem(UINavigationBar navigationBar, UINavigationItem item)
{ {
@ -96,7 +84,12 @@ namespace Xamarin.Forms.Platform.iOS
if (allowPop) if (allowPop)
{ {
// Do not remove, wonky behavior on some versions of iOS if you dont dispatch // Do not remove, wonky behavior on some versions of iOS if you dont dispatch
CoreFoundation.DispatchQueue.MainQueue.DispatchAsync(() => PopViewController(true)); CoreFoundation.DispatchQueue.MainQueue.DispatchAsync(() =>
{
_popCompletionTask = new TaskCompletionSource<bool>();
SendPoppedOnCompletion(_popCompletionTask.Task);
PopViewController(true);
});
} }
else else
{ {
@ -267,9 +260,7 @@ namespace Xamarin.Forms.Platform.iOS
_popCompletionTask = new TaskCompletionSource<bool>(); _popCompletionTask = new TaskCompletionSource<bool>();
e.Task = _popCompletionTask.Task; e.Task = _popCompletionTask.Task;
_ignorePop = true;
PopViewController(animated); PopViewController(animated);
_ignorePop = false;
await _popCompletionTask.Task; await _popCompletionTask.Task;
@ -500,6 +491,20 @@ namespace Xamarin.Forms.Platform.iOS
navBarVisible = Shell.GetNavBarIsVisible(element); navBarVisible = Shell.GetNavBarIsVisible(element);
navigationController.SetNavigationBarHidden(!navBarVisible, true); navigationController.SetNavigationBarHidden(!navBarVisible, true);
var coordinator = viewController.GetTransitionCoordinator();
if (coordinator != null)
{
// handle swipe to dismiss gesture
coordinator.NotifyWhenInteractionEndsUsingBlock((context) =>
{
if (!context.IsCancelled)
{
_self._popCompletionTask = new TaskCompletionSource<bool>();
_self.SendPoppedOnCompletion(_self._popCompletionTask.Task);
}
});
}
} }
} }
} }

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

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="using:Xamarin.Forms.Xaml.UnitTests"
x:Class="Xamarin.Forms.Xaml.UnitTests.Gh8936"
x:DataType="local:Gh8936VM">
<Entry x:Name="entry0" Text="{Binding Data[Key]}" />
</ContentPage>

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

@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using NUnit.Framework;
using Xamarin.Forms;
using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
public class Dict : Dictionary<string,string> {}
public class Gh8936VM
{
public Dict Data { get; set; } = new Dict { { "Key", "Value" } };
}
public partial class Gh8936 : ContentPage
{
public Gh8936() => InitializeComponent();
public Gh8936(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}
[TestFixture]
class Tests
{
[SetUp] public void Setup() => Device.PlatformServices = new MockPlatformServices();
[TearDown] public void TearDown() => Device.PlatformServices = null;
[Test]
public void IndexerBindingOnSubclasses([Values(false, true)]bool useCompiledXaml)
{
var layout = new Gh8936(useCompiledXaml) { BindingContext = new Gh8936VM() };
Assert.That(layout.entry0.Text, Is.EqualTo("Value"));
layout.entry0.Text = "Bar";
Assert.That(layout.entry0.Text, Is.EqualTo("Bar"));
Assert.That(((Gh8936VM)layout.BindingContext).Data["Key"], Is.EqualTo("Bar"));
}
}
}
}