我遇到过OnPropertyChanged处理程序在cutom渲染器中为同一属性多次执行的问题。我创建了示例项目来重现该问题。 我有以下表格与TableView:
<?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="clr-namespace:IssueWithEvents"
xmlns:components="clr-namespace:IssueWithEvents.Components;assembly=IssueWithEvents"
x:Class="IssueWithEvents.MainPage">
<TableView Intent="Form" HasUnevenRows="True">
<TableRoot>
<TableSection Title="Sample Form">
<EntryCell Label="Item 1"></EntryCell>
<EntryCell Label="Item 2"></EntryCell>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="Item 3"/>
<components:CustomEntry x:Name="MyEntry" HorizontalOptions="FillAndExpand" Text="{Binding Counter}"></components:CustomEntry>
<Button Text="Push" Clicked="Button_OnClicked"></Button>
</StackLayout>
</ViewCell>
<EntryCell Label="Item 4"></EntryCell>
<EntryCell Label="Item 5"></EntryCell>
<EntryCell Label="Item 6"></EntryCell>
<EntryCell Label="Item 7"></EntryCell>
<EntryCell Label="Item 8"></EntryCell>
<EntryCell Label="Item 9"></EntryCell>
<EntryCell Label="Item 10"></EntryCell>
<EntryCell Label="Item 11"></EntryCell>
<EntryCell Label="Item 12"></EntryCell>
<EntryCell Label="Item 13"></EntryCell>
<EntryCell Label="Item 14"></EntryCell>
<EntryCell Label="Item 15"></EntryCell>
<EntryCell Label="Item 16"></EntryCell>
<EntryCell Label="Item 17"></EntryCell>
<EntryCell Label="Item 18"></EntryCell>
</TableSection>
</TableRoot>
</TableView>
</ContentPage>
这是代码隐藏:
using System.Diagnostics;
using Xamarin.Forms;
namespace IssueWithEvents
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = this;
}
public int Counter
{
get { return (int)GetValue(CounterProperty); }
set { SetValue(CounterProperty, value); }
}
public static readonly BindableProperty CounterProperty = BindableProperty.Create("Counter", typeof(int), typeof(MainPage), 0);
private void Button_OnClicked(object sender, EventArgs e)
{
Debug.WriteLine("Button clicked");
Counter++;
MyEntry.SampleProperty = Counter.ToString();
}
}
}
其中一个单元格中包含自定义组件的自定义布局。 CustomEntry组件只是从Entry派生的简单组件,具有一个附加属性:
using Xamarin.Forms;
namespace IssueWithEvents.Components
{
public class CustomEntry:Entry
{
private string _sampleProperty;
public string SampleProperty
{
get { return _sampleProperty; }
set
{
_sampleProperty = value;
OnPropertyChanged();
}
}
}
}
这是渲染器:
using System.ComponentModel;
using IssueWithEvents.Components;
using IssueWithEvents.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryRenderer))]
namespace IssueWithEvents.Droid.Renderers
{
public class CustomEntryRenderer:EntryRenderer
{
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == "SampleProperty")
{
System.Diagnostics.Debug.WriteLine("SampleProperty Changed");
}
}
}
}
在运行并按下按钮后,调试中的输出就可以了:
[0:] Button clicked
[0:] SampleProperty Changed
然后,如果我滚动列表,以便自定义单元格消失,然后向后滚动并按下按钮,输出将如下:
[0:] Button clicked
[0:] SampleProperty Changed
[0:] SampleProperty Changed
每次将自定义单元格滚出屏幕然后向后滚动时,事件处理程序执行次数将会增加:
[0:] Button clicked
[0:] SampleProperty Changed
[0:] SampleProperty Changed
[0:] SampleProperty Changed
[0:] SampleProperty Changed
[0:] SampleProperty Changed
我花了几天时间尝试解决这个问题,但没有成功。 我能找到的是用于单元重用的代码不能正确处理先前的单元格内容而不能取消订阅onPropertyChanged事件。 所以它看起来像bug,但也许我做错了,或者有人知道要解决这个问题。
谢谢!