自定义控件中的Xamarin.Forms绑定集合

时间:2019-09-13 10:32:22

标签: c# xaml xamarin xamarin.forms data-binding

我正在尝试创建一个自定义控件,该控件内部具有ListView并填充在父控件中。这是代码:

用于测试的模型(TestModel.cs):

public class TestModel
{
    public string TestText { get; set; }

    public TestModel(string text)
    {
        TestText = text;
    }
}

自定义控件代码(TestControl.xaml.cs):

public partial class TestControl : ContentView
{
    public static readonly BindableProperty TestItemsProperty =
            BindableProperty.Create(nameof(TestItems), typeof(ObservableCollection<TestModel>), typeof(TestControl), default);
    public ObservableCollection<TestModel> TestItems
    {
        get => (ObservableCollection<TestModel>)GetValue(TestItemsProperty);
        set => SetValue(TestItemsProperty, value);
    }

    public TestControl()
    {
        InitializeComponent();
        BindingContext = this;
    }
}

自定义控件XAML(TestControl.xaml):

<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="SalesNet.Mobile.Controls.TestControl">
    <StackLayout>
        <ListView ItemsSource="{Binding TestItems}"
                  x:Name="lv">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Label Text="{Binding TestText}"/>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentView>

包含控件(TestViewModel.cs)的页面的视图模型:

public class TestViewModel : BaseViewModel
{
    private ObservableCollection<TestModel> testModels;
    public ObservableCollection<TestModel> TestModels
    {
       get { return testModels; }
       set { SetProperty(ref testModels, value); }
    }

    public Command LoadTestModels { get; set; }

    public TestViewModel()
    {
        var models = new List<TestModel>()
        {
            new TestModel("a"),
            new TestModel("b")
        };

        TestModels = new ObservableCollection<TestModel>(models);
        LoadTestModels = new Command(async () => await ExecuteLoadTestModels());
    }

    private async Task ExecuteLoadTestModels()
    {
        IsBusy = true;
        await Task.Delay(2000);

        var models = new List<TestModel>()
        {
            new TestModel("a"),
            new TestModel("b"),
            new TestModel("c")
        };

        // I have tried this
        TestModels.Clear();
        foreach (var model in models)
           TestModels.Add(model);

        // And this
        TestModels = new ObservableCollection<TestModel>(models);

        IsBusy = false;
    }
}

包含控件的页面,代码(TestPage.xaml.cs):

public partial class TestPage : ContentPage
{
    private TestViewModel viewModel;

    public TestPage()
    {
        InitializeComponent();

        BindingContext = viewModel = new TestViewModel();
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();

        viewModel.LoadTestModels.Execute(null);
    }
}

包含控件XAML(TestPage.xaml)的页面:

<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"
             xmlns:controls="clr-namespace:SalesNet.Mobile.Controls"
             mc:Ignorable="d"
             x:Class="SalesNet.Mobile.Views.TestPage">
    <ContentPage.Content>
        <controls:TestControl TestItems="{Binding TestModels}"/>
    </ContentPage.Content>
</ContentPage>

我遇到的问题是该集合没有从父项传播到自定义控件。我尝试过重新声明和重新填充集合。这仅在集合中发生。我还尝试过在自定义控件(TestControl.xaml.cs)中编写OnPropertyChanged事件,但没有触发。

1 个答案:

答案 0 :(得分:1)

在自定义控件中添加以下方法

public static readonly BindableProperty TestItemsProperty =
            BindableProperty.Create(
                propertyName: "TestItems",
                returnType: typeof(ObservableCollection<TestModel>),
                declaringType: typeof(TestControl ),
                propertyChanged: OnEventNameChanged);
static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
{
            Console.WriteLine(newValue.ToString());
            var control = (View1)bindable;
            control.lv.ItemsSource = newValue as ObservableCollection<TestModel>;
}

并从构造函数中删除该行

BindingContext = this;