【问题标题】:Xamarin.Forms Binding Collection in Custom Control自定义控件中的 Xamarin.Forms 绑定集合
【发布时间】:2019-09-13 10:32:22
【问题描述】:

我正在尝试创建一个自定义控件,其中包含一个 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 事件,但它没有触发。

【问题讨论】:

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


    【解决方案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;
    

    【讨论】:

    • 这确实有效,谢谢!您能否解释一下为什么需要属性更改事件以及为什么需要删除将 BindingContext 设置为此?
    • 这似乎是 XF 4.x 的现有问题,我会再次检查它:)
    • @LucasZhang-MSFT,我已经把头发扯了大约 4 个小时,想知道为什么绑定到我的用户控件不起作用,但它对所有平台控件都非常满意这页纸。这已经解决了。 XF4 中的绑定是否损坏?我不明白为什么需要 PropertyChanged 事件,或者删除 BindingContext=this。这似乎没有任何意义。感觉就像我们绕过了应该处理这个问题的系统。你能澄清一下吗? (我在 XF4.7.0.1239 上)
    • 显然,当您希望在自己的控件和“外部”之间进行数据绑定时,您也不能在控件的内部 中使用数据绑定。相反,您必须按名称访问子控件以设置(或获取)它们的值
    猜你喜欢
    • 2018-02-17
    • 1970-01-01
    • 2013-12-25
    • 2014-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-20
    • 1970-01-01
    相关资源
    最近更新 更多