1

I'm creating a custom view in xamarin Forms with a set of Bindable properties including Bindable observable collections type of my own Models. These observable collections serves as data source for custom view and gets updated in realtime. Everything was fine until different types of models added and code refactoring started.

There are few set of Models that custom view supports and any point of time there can be only one observable collection of type any model. Initially I managed with different properties for each type, then to make it more generic I tried handling it with single property. That is when I replaced

In CustomView.cs

ObservableCollection<ModelA> ADataSource ObservableCollection<ModelB> BDataSource

with

ObservableCollection<object> DataSource

In ViewModel I have

ObservableCollection<ModelA> AList

Now when app runs it Custom View throws an error "Specific Cast is not valid" for the generic observable collection. While debugging in Property_Changing event handler I am able to caste the newValue through quick watch to Observable Collection.

How to handle this and make the generic observable collection property support multi type models.

Thanks in Advance


If you want to use ObservableCollection modelbs bindable property in ContentView, then use this custom control in ContentPage, I do one sample that you can take a look:

ContentView:

<ContentView
x:Class="demo3.contentview.View2"
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"
x:Name="customlistview"
mc:Ignorable="d">
<ContentView.Content>
    <StackLayout>
        <ListView x:Name="listview1" ItemsSource="{Binding Items, Source={x:Reference customlistview}}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout>
                            <Label Text="{Binding name}" />
                            <Label Text="{Binding age}" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentView.Content>

 public partial class View2 : ContentView
{
    public static  BindableProperty ItemsProperty = BindableProperty.Create("ItemsSource", typeof(ObservableCollection<object>), typeof(View2),null,BindingMode.TwoWay,propertyChanged: (bindable, oldValue, newValue) => OnItemsSourceChanged(bindable, oldValue, newValue));

    private static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var control =(View2)bindable;
        control.listview1.ItemsSource =(ObservableCollection<object>) newValue;
    }
    /// <summary>
    /// Accessors
    /// </summary>
    public ObservableCollection<object> Items
    {
        get { return (ObservableCollection<object>)GetValue(ItemsProperty); }
        set
        {
            SetValue(ItemsProperty, value);
        }
    }
    public View2()
    {
        InitializeComponent();

    }
}

ContentPage:

 <ContentPage.Content>
    <StackLayout>
        <local:View2 Items="{Binding modelas}" />

    </StackLayout>
</ContentPage.Content>

public partial class Page26 : ContentPage
{
    public ObservableCollection<object> modelas {get;set;}
    public ObservableCollection<object> modelbs { get; set; }
    public Page26()
    {
        InitializeComponent();
        modelas = new ObservableCollection<object>()
        {
            new modela(){name="cherry",age=12},
            new modela(){name="barry",age=20}
        };

        modelbs = new ObservableCollection<object>()
        {
            new modelb(){firstname="aaa",age=12},
            new modelb(){firstname="bbb",age=27}
        };
        this.BindingContext = this;

    }
}

public class modela
{
    public string name { get; set; }
    public int age { get; set; }
}

public class modelb
{
    public string firstname { get; set; }
    public int age { get; set; }
}
4

1 回答 1

1

如果你想在 ContentView 中使用 ObservableCollection modelbs 可绑定属性,那么在 ContentPage 中使用这个自定义控件,我做了一个示例,你可以看看:

内容视图:

<ContentView
x:Class="demo3.contentview.View2"
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"
x:Name="customlistview"
mc:Ignorable="d">
<ContentView.Content>
    <StackLayout>
        <ListView x:Name="listview1" ItemsSource="{Binding Items, Source={x:Reference customlistview}}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout>
                            <Label Text="{Binding name}" />
                            <Label Text="{Binding age}" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentView.Content>

 public partial class View2 : ContentView
{
    public static  BindableProperty ItemsProperty = BindableProperty.Create("ItemsSource", typeof(ObservableCollection<object>), typeof(View2),null,BindingMode.TwoWay,propertyChanged: (bindable, oldValue, newValue) => OnItemsSourceChanged(bindable, oldValue, newValue));

    private static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var control =(View2)bindable;
        control.listview1.ItemsSource =(ObservableCollection<object>) newValue;
    }
    /// <summary>
    /// Accessors
    /// </summary>
    public ObservableCollection<object> Items
    {
        get { return (ObservableCollection<object>)GetValue(ItemsProperty); }
        set
        {
            SetValue(ItemsProperty, value);
        }
    }
    public View2()
    {
        InitializeComponent();

    }
}

内容页:

 <ContentPage.Content>
    <StackLayout>
        <local:View2 Items="{Binding modelas}" />

    </StackLayout>
</ContentPage.Content>

public partial class Page26 : ContentPage
{
    public ObservableCollection<object> modelas {get;set;}
    public ObservableCollection<object> modelbs { get; set; }
    public Page26()
    {
        InitializeComponent();
        modelas = new ObservableCollection<object>()
        {
            new modela(){name="cherry",age=12},
            new modela(){name="barry",age=20}
        };

        modelbs = new ObservableCollection<object>()
        {
            new modelb(){firstname="aaa",age=12},
            new modelb(){firstname="bbb",age=27}
        };
        this.BindingContext = this;

    }
}

public class modela
{
    public string name { get; set; }
    public int age { get; set; }
}

public class modelb
{
    public string firstname { get; set; }
    public int age { get; set; }
}
于 2020-03-06T03:03:38.660 回答