【问题标题】:Xamarin TimePicker propertychanged event fired on load加载时触发 Xamarin TimePicker propertychanged 事件
【发布时间】:2016-11-12 23:40:20
【问题描述】:

我正在为 Android 开发一个 Xamarin 应用程序,使用 Xamarin 表单来创建我的布局。我遇到了一个问题,我的时间选择器在加载我的视图单元时触发。

我正在做的是创建一个列表视图,然后将项目模板设置为我的自定义视图单元格模板。在我的视图单元格模板中,我正在创建一个 TimePicker 并将 PropertyChanged 事件绑定到它。我还使用从数据库中检索到的信息设置 TimePicker.Time 属性。此时似乎发生的是,我的 PropertyChanged 事件为将显示在列表视图中的每个项目触发。这会导致不需要的多个数据库调用。

有没有办法阻止 PropertyChanged 事件被调用,直到一个属性实际被更改?

我的代码如下。

public class MyCell : ViewCell
{
private readonly TimePicker _myTimePicker;
public MyCell()
{
   _myTimePicker = new TimePicker()
        {
            HorizontalOptions = LayoutOptions.EndAndExpand
        };

        _myTimePicker.SetBinding(TimePicker.TimeProperty, "StartTime");
        _myTimePicker.PropertyChanged += MyTimePicker_PropertyChanged;

        var viewLayout = new StackLayout()
        {
            HorizontalOptions = LayoutOptions.StartAndExpand,
            Orientation = StackOrientation.Horizontal,
            Padding = new Thickness(20),
            Children = { _myTimePicker }
        };
        View = viewLayout;
}

private void MyTimePicker_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == TimePicker.TimeProperty.PropertyName && _myTimePicker.Time != TimeSpan.MinValue)
        {
            var dataAccess = new DataAccessLayer();
            dataAccess.Update(myTimePicker.Time);
        }
    }
}

我不确定为什么 propertychanged 事件会被多次触发,以及如何在我实际选择时间之前阻止它触发。任何帮助将不胜感激。

下面是我用于显示列表视图的表单代码。我所有的 xaml 都是在代码中定义的。 “MyCell”使用从“_dataAccess.GetTimes()”返回的值。

public class TimeDetails : ContentPage
{
    private ListView _listView;
    private readonly DataAccessLayer _dataAccess = new DataAccessLayer();

    protected override void OnAppearing()
    {
        _listView = new ListView
        {
            RowHeight = 80,
            SeparatorColor = Color.Blue,
            SeparatorVisibility = SeparatorVisibility.Default
        };

        _listView.ItemsSource = _dataAccess.GetTimes();
        _listView.ItemTemplate = new DataTemplate(typeof(MyCell));
        _listView.ItemSelected += ListView_ItemSelected;

        Content = new StackLayout
        {
            VerticalOptions = LayoutOptions.FillAndExpand,
            Children = { _listView }
        };
    }
}

_dataAcess.GetTimes() 的返回类型是TaskTime 列表。 TaskTime 模型如下所示。

public class TaskTime
{
    public int Id { get; set; }
    public string Task { get; set; }
    public TimeSpan StartTime { get; set; }
}

【问题讨论】:

  • 我假设您发布的这段代码在您的页面中?您还可以发布您的 xaml 和代码如何绑定到 listview 吗?特别是您分配 ItemSource 和 ItemBindingTemplate 的位置。目前尚不清楚您是在 xaml 中还是在代码中的某个地方执行此操作。然后我可以尝试重现
  • 我最初发布的代码在我的自定义单元格中,该单元格在我的列表视图项模板中使用。我已使用您要求的信息对原始问题进行了编辑。谢谢。
  • MyCell 是从什么东西派生的吗?我看到 View = viewLayout;但 MyCell 中没有视图。还有什么 _dataAccess.GetTimes();回报? listView 中没有定义绑定。你能把整个源代码放在某个地方,以便我更快地帮助你吗?
  • 更新是上面提出的问题。我不知道我可以把代码放在哪里让你看看。
  • Dropbox 或 github

标签: android xamarin xamarin.forms timepicker propertychanged


【解决方案1】:
class MyCell : ViewCell
{
    private readonly TimePicker _myTimePicker;
    public MyCell()
    {
        _myTimePicker = new TimePicker()
        {
            HorizontalOptions = LayoutOptions.EndAndExpand
        };

        _myTimePicker.SetBinding(TimePicker.TimeProperty, "StartTime");
        _myTimePicker.PropertyChanged += MyTimePicker_PropertyChanged;
        _myTimePicker.Focused += _myTimePicker_Focused;

        var viewLayout = new StackLayout()
        {
            HorizontalOptions = LayoutOptions.StartAndExpand,
            Orientation = StackOrientation.Horizontal,
            Padding = new Thickness(20),
            Children = { _myTimePicker }
        };
        View = viewLayout;
    }

    bool myTimePickerSelected;
    private void _myTimePicker_Focused(object sender, FocusEventArgs e)
    {
        myTimePickerSelected = true;
    }

    private void MyTimePicker_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {

        if (e.PropertyName == TimePicker.TimeProperty.PropertyName && myTimePickerSelected)
        {
            //var dataAccess = new DataAccessLayer();
            //dataAccess.Update(myTimePicker.Time);
        }
    }
}

【讨论】:

  • 确实有道理。你知道有什么方法可以阻止这种情况吗?
  • 是的。不要订阅属性更改,但是您将不知道何时选择了时间
  • 我确实需要知道何时选择时间,因为需要使用所选时间更新数据库。我会和其他东西一起玩,看看我能不能绕过它。
  • 我已经设法解决了这个问题,你可以在我发布它作为答案之前告诉我它是否是一个好的解决方案。我创建了一个新的 TimePicker 并将“StartTime”的值设置为它(与我对 _myTimePicker 所做的一样)。然后添加到 if 语句并比较我的两个 TimePicker 的值。当我修改 _myTimePicker 时,值不同,因此属性更改事件中的更新代码运行。在那里,我现在还将新的 TimePicker 设置为 _myTimePicker 的新值。听起来怎么样?
  • 添加另一个时间选择器是开销。只有时间跨度就足够了。我已经更新了我的答案。
【解决方案2】:

使用有焦点和无焦点事件的更简单的解决方案是:

public class CustomTimePicker : TimePicker
{
    public event EventHandler TimeChanged;

    private TimeSpan StartValue { get; set; }

    public CustomTimePicker ()
    {
        this.Focused += OnFoused;
        this.Unfocused += OnUnfocused;
    }

    private void OnFoused(object sender, FocusEventArgs e)
    {
        StartValue = this.Time;
    }

    private void OnUnfocused(object sender, FocusEventArgs e)
    {
        if (StartValue != this.Time)
        {
            TimeChanged?.Invoke(this, e);
        }
    }
}

【讨论】:

    【解决方案3】:

    我所看到的是,当所有初始化完成后,OnAppearing() 就完成了。也许您可以引入一个布尔变量,然后在 PropertyChanged() 方法中使用它。这是一个技巧,因为您必须从ContentPage 执行此操作,并在初始化完成时将值传递给您的控件。 我刚刚看到,CellView 中有OnAppearing() 方法,这样一切都在你的控件类中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-08
      • 2021-09-27
      • 1970-01-01
      • 2022-06-10
      相关资源
      最近更新 更多