BindableProperty仅触发一次

时间:2020-04-10 11:41:42

标签: mvvm xamarin.forms

我有一个内容视图,该视图具有一个绑定到父级ViewModel的BindableProperty。收到新值时,绑定到BindableProperty的属性将触发一个方法,该方法可在内容视图内以编程方式创建一组新的控件。仅当为父视图设置BindingContext时,才会触发BindableProperty。有人可以告诉我我在做什么错吗?

编辑

看来,更正BindableProperty.Create中的第三个参数(从typeof(CalendarControlModel)typeof(Calendar)并添加BindingMode.TwoWay,就可以解决问题。

新问题:为什么在这里需要双向绑定?

后面的内容查看代码

public partial class Calendar
{
    public static readonly BindableProperty AppointmentsDataProperty = BindableProperty.Create(nameof(AppointmentsData), typeof(CalendarControlModel), typeof(Calendar), new CalendarControlModel(),BindingMode.TwoWay
        propertyChanged: (bindableObject, oldValue, newValue) =>
        {
            if (bindableObject is Calendar view)
            {
                view.AppointmentsData = (CalendarControlModel)newValue;
            }
        });

    public CalendarControlModel AppointmentsData { get { return (CalendarControlModel)GetValue(AppointmentsDataProperty); } set { SetValue(AppointmentsDataProperty, value); PrepareAppointments(); } }

    public Calendar()
    {
        InitializeComponent();
    }

    private void PrepareAppointments()
    {
        ....
        MainScrollView.Content = meetingsGrid;
    }

内容视图

<?xml version="1.0" encoding="UTF-8"?>
<ContentView 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="NS.Controls.Calendar">
    <ContentView.Content>
        <ScrollView x:Name="MainScrollView">
        </ScrollView>
    </ContentView.Content>
</ContentView>

查看模型

class CalendarPageViewModel : BaseViewModel
{
    private DailyCalendarControlModel appointmentsData;
    public ObservableCollection<PickerModel> AppointmentTypes { get; set; }
    public DailyCalendarControlModel AppointmentsData
    {
        get => appointmentsData;
        set => SetProperty(ref appointmentsData, value);
    }
    public PickerModel SelectedAppointmentType { get; set; }
    public CalendarSummaryModel Summary { get; set; }

    public ICommand SwitchDayCommand { get; set; }

    public ICommand SwitchAppointmentType { get; set; }

    public DailyCalendarPageViewModel()
    {
        SwitchDayCommand = new Command<DateTime>(date =>
        {
            if (date.Day % 2 == 1)
            {
                AppointmentsData = new DailyCalendarControlModel
                {
                    Appointments = DataGenerators.GenerateAppointmentsList1(),
                    Schedule = DataGenerators.GenerateSchedule()
                };
            }
            else
            {
                AppointmentsData = new DailyCalendarControlModel
                {
                    Appointments = DataGenerators.GenerateAppointmentsList2(),
                    Schedule = DataGenerators.GenerateSchedule()
                };
            }
        });

        SwitchAppointmentType = new Command<int>(type =>
            {

            });
    }
}

父页面浏览量

<?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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:controls="clr-namespace:NS.Controls;assembly=NS"
             mc:Ignorable="d"
             x:Class="NS.Views.CalendarPage">
    <ContentPage.Content>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <controls:PageHeader  NextDayCommand="{Binding SwitchDayCommand}" PreviousDayCommand="{Binding SwitchDayCommand}" ChangedTypeCommand="{Binding SwitchAppointmentType}" />
            <controls:Calendar x:Name="CalendarControl" AppointmentsData="{Binding AppointmentsData}"  Grid.Row="1"  />
            <controls:CalendarSummary Summary="{Binding Summary}" Grid.Row="2" />
        </Grid>
    </ContentPage.Content>
</ContentPage>

父页面背后的代码

public partial class CalendarPage : ContentPage
{
    public CalendarPage()
    {
        InitializeComponent();

        var appointmentTypes = EnumFactories.CreateFromEventType();

        CalendarPageViewModel model = new CalendarPageViewModel
        {
            SelectedAppointmentType = appointmentTypes.FirstOrDefault(a => a.Id == (int)EventType.Consultation),
            AppointmentTypes = appointmentTypes,
            //SelectedDate = DateTime.Now.Date,
            AppointmentsData = new CalendarControlModel {Appointments = DataGenerators.GenerateAppointmentsList(), Schedule = DataGenerators.GenerateSchedule() },
            Summary = new CalendarSummaryModel
            {
                AppointmentsSummaries = $"Cabinet1",
                TotalAppointments = "5",
                TotalSum = "1"
            }
        };

        BindingContext = model;
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();
        CalendarControl.ScrollToCurrentTime();
    }
}

1 个答案:

答案 0 :(得分:1)

public static readonly BindableProperty AppointmentsDataProperty = BindableProperty.Create(nameof(AppointmentsData), typeof(CalendarControlModel), typeof(CalendarControlModel), new CalendarControlModel(),
        propertyChanged: (bindableObject, oldValue, newValue) =>
        {
            if (bindableObject is Calendar view)
            {
                view.AppointmentsData = (CalendarControlModel)newValue;
            }
        });

nameof(AppointmentsData):这提供了存储信息的属性的名称。

typeof(CalendarControlModel)::这是属性的类型。

typeof(CalendarControlModel)::这是属性所在类的类型。

新的CalendarControlModel():这只是默认值。

似乎您为第三个属性设置了错误的值

此外,您应该直接在PropertyChanged中设置UI,否则需要将绑定模式设置为 TwoWay

因此,请按照以下说明改进代码

public static readonly BindableProperty AppointmentsDataProperty = BindableProperty.Create(nameof(AppointmentsData), typeof(CalendarControlModel), typeof(Calendar), new CalendarControlModel(),BindingMode.OneWay,
            propertyChanged: (bindableObject, oldValue, newValue) =>
            {
                if (bindableObject is Calendar view)
                {
                   var model = newValue as CalendarControlModel;

                    var label = new Label { Text = $"{model.Hour}:{model.Minute}", HorizontalTextAlignment = TextAlignment.Center, FontSize = 32 };

                    view.MainScrollView.Content = label;



                }
            });