Don't force binding expression applications to queue (#6857)
* Don't force binding expression applications to queue; fixes #6609 * Make PropertyChangeBindingsOccurThroughMainThread test what it claims to test
This commit is contained in:
Родитель
8931dbd8ee
Коммит
5bc931f089
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
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.CollectionView)]
|
||||
#endif
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 6609, "[Bug, CollectionView] SelectionChangedCommand invoked before SelectedItem is set",
|
||||
PlatformAffected.All)]
|
||||
public class Issue6609 : TestNavigationPage
|
||||
{
|
||||
protected override void Init()
|
||||
{
|
||||
#if APP
|
||||
FlagTestHelpers.SetCollectionViewTestFlag();
|
||||
|
||||
PushAsync(new GalleryPages.CollectionViewGalleries.SelectionGalleries.SelectionChangedCommandParameter());
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UITEST
|
||||
[Test]
|
||||
public void SelectionChangedCommandParameterBoundToSelectedItemShouldMatchSelectedItem()
|
||||
{
|
||||
RunningApp.WaitForElement("Item 2");
|
||||
RunningApp.Tap("Item 2");
|
||||
|
||||
RunningApp.WaitForElement("Success");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
<DependentUpon>Issue5046.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue6609.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ShellInsets.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewGrouping.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue5412.cs" />
|
||||
|
@ -528,7 +529,7 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla39853.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)MultipleClipToBounds.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)_TemplateMarkup.xaml.cs">
|
||||
<DependentUpon>_TemplateMarkup.xaml</DependentUpon>
|
||||
<DependentUpon>_TemplateMarkup.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)PerformanceGallery\PerformanceDataManager.cs" />
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<?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:d="http://xamarin.com/schemas/2014/forms/design"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
x:Class="Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.SelectionGalleries.SelectionChangedCommandParameter">
|
||||
<ContentPage.Content>
|
||||
<StackLayout>
|
||||
|
||||
<Label x:Name="Result" Text="Pending..."></Label>
|
||||
|
||||
<CollectionView ItemsSource="{Binding Items}"
|
||||
SelectionMode="Single"
|
||||
SelectionChangedCommandParameter="{Binding SelectedItem,Source={x:Reference MyCollectionView}}"
|
||||
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
|
||||
SelectionChangedCommand="{Binding SelectionChangedCommand}"
|
||||
x:Name="MyCollectionView">
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackLayout Padding="10">
|
||||
<Label Text="{Binding Text}"
|
||||
d:Text="{Binding .}"
|
||||
LineBreakMode="NoWrap"
|
||||
Style="{DynamicResource ListItemTextStyle}"
|
||||
FontSize="16" />
|
||||
<Label Text="{Binding Description}"
|
||||
d:Text="Item description"
|
||||
LineBreakMode="NoWrap"
|
||||
Style="{DynamicResource ListItemDetailTextStyle}"
|
||||
FontSize="13" />
|
||||
</StackLayout>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</StackLayout>
|
||||
|
||||
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
|
@ -0,0 +1,88 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Internals;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.SelectionGalleries
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class SelectionChangedCommandParameter : ContentPage
|
||||
{
|
||||
public SelectionChangedCommandParameter()
|
||||
{
|
||||
InitializeComponent();
|
||||
BindingContext = new ItemsViewModel(Result);
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
class Item
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Text { get; set; }
|
||||
public string Description { get; set; }
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
class ItemsViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public ObservableCollection<Item> Items { get; set; }
|
||||
public Command LoadItemsCommand { get; set; }
|
||||
|
||||
Item _selectedItem;
|
||||
readonly Label _result;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public Item SelectedItem
|
||||
{
|
||||
get => _selectedItem;
|
||||
set { _selectedItem = value; OnPropertyChanged(); }
|
||||
}
|
||||
|
||||
public Command<Item> SelectionChangedCommand { get; }
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
|
||||
{
|
||||
var changed = PropertyChanged;
|
||||
if (changed == null)
|
||||
return;
|
||||
|
||||
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public ItemsViewModel(Label result)
|
||||
{
|
||||
Items = new ObservableCollection<Item>();
|
||||
|
||||
for (int n = 0; n < 10; n++)
|
||||
{
|
||||
Items.Add(new Item { Id = n.ToString(), Text = $"Item {n}", Description = $"This is item {n}" });
|
||||
}
|
||||
|
||||
SelectionChangedCommand = new Command<Item>(item =>
|
||||
{
|
||||
var fromParameter = item;
|
||||
var fromSelectedItem = SelectedItem;
|
||||
|
||||
if (fromParameter != fromSelectedItem)
|
||||
{
|
||||
_result.Text = "Fail";
|
||||
}
|
||||
else
|
||||
{
|
||||
_result.Text = "Success";
|
||||
}
|
||||
});
|
||||
_result = result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,6 +26,8 @@
|
|||
new SingleBoundSelection(), Navigation),
|
||||
GalleryBuilder.NavButton("Multiple Selection, Bound", () =>
|
||||
new MultipleBoundSelection(), Navigation),
|
||||
GalleryBuilder.NavButton("SelectionChangedCommandParameter", () =>
|
||||
new SelectionChangedCommandParameter(), Navigation),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -65,6 +65,9 @@
|
|||
<EmbeddedResource Update="GalleryPages\CollectionViewGalleries\DataTemplateSelectorGallery.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="GalleryPages\CollectionViewGalleries\SelectionGalleries\SelectionChangedCommandParameter.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="GalleryPages\MapGallery.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
|
|
|
@ -614,7 +614,7 @@ namespace Xamarin.Forms.Core.UnitTests
|
|||
bindable.SetBinding(MockBindable.TextProperty, binding);
|
||||
|
||||
bool invokeOnMainThreadWasCalled = false;
|
||||
Device.PlatformServices = new MockPlatformServices(a => invokeOnMainThreadWasCalled = true);
|
||||
Device.PlatformServices = new MockPlatformServices(a => invokeOnMainThreadWasCalled = true, isInvokeRequired: true);
|
||||
|
||||
vm.Text = "updated";
|
||||
|
||||
|
|
|
@ -25,17 +25,19 @@ namespace Xamarin.Forms.Core.UnitTests
|
|||
Func<Uri, CancellationToken, Task<Stream>> getStreamAsync;
|
||||
Func<VisualElement, double, double, SizeRequest> getNativeSizeFunc;
|
||||
readonly bool useRealisticLabelMeasure;
|
||||
readonly bool _isInvokeRequired;
|
||||
|
||||
public MockPlatformServices (Action<Action> invokeOnMainThread = null, Action<Uri> openUriAction = null,
|
||||
Func<Uri, CancellationToken, Task<Stream>> getStreamAsync = null,
|
||||
Func<VisualElement, double, double, SizeRequest> getNativeSizeFunc = null,
|
||||
bool useRealisticLabelMeasure = false)
|
||||
bool useRealisticLabelMeasure = false, bool isInvokeRequired = false)
|
||||
{
|
||||
this.invokeOnMainThread = invokeOnMainThread;
|
||||
this.openUriAction = openUriAction;
|
||||
this.getStreamAsync = getStreamAsync;
|
||||
this.getNativeSizeFunc = getNativeSizeFunc;
|
||||
this.useRealisticLabelMeasure = useRealisticLabelMeasure;
|
||||
_isInvokeRequired = isInvokeRequired;
|
||||
}
|
||||
|
||||
static MD5CryptoServiceProvider checksum = new MD5CryptoServiceProvider ();
|
||||
|
@ -85,7 +87,7 @@ namespace Xamarin.Forms.Core.UnitTests
|
|||
|
||||
public bool IsInvokeRequired
|
||||
{
|
||||
get { return false; }
|
||||
get { return _isInvokeRequired; }
|
||||
}
|
||||
|
||||
public string RuntimePlatform { get; set; }
|
||||
|
|
|
@ -615,7 +615,14 @@ namespace Xamarin.Forms
|
|||
}
|
||||
}
|
||||
|
||||
Device.BeginInvokeOnMainThread(() => _expression.Apply());
|
||||
if (Device.IsInvokeRequired)
|
||||
{
|
||||
Device.BeginInvokeOnMainThread(() => _expression.Apply());
|
||||
}
|
||||
else
|
||||
{
|
||||
_expression.Apply();
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetValue(object source, out object value)
|
||||
|
|
Загрузка…
Ссылка в новой задаче