Как привязать ItemsSource из CollectionView в пользовательском элементе управления?

#c# #xamarin.forms

#c# #xamarin.forms

Вопрос:

Я создаю пользовательский элемент управления с помощью CollectionView. Проблема в том, что я хочу предоставить ему ItemsSource с главной страницы, а не из элемента управления, и что ItemsSource связывает его с моей ViewModel, где находится моя ObservableCollection. Это мой код:

FloatingButton.xaml:

 <?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomControlWithList.FloatingButton"
             x:Name="FloatingButtonView">


    <StackLayout>

        <AbsoluteLayout>
            <CollectionView
                x:Name="listView"
                Margin="0,0,36,0"
                AbsoluteLayout.LayoutBounds="1,0,AutoSize,AutoSize"
                AbsoluteLayout.LayoutFlags="PositionProportional"
                BackgroundColor="Transparent"
                ItemsSource="{Binding ItemSource}"
                IsVisible="{Binding IsVisible}"
                Rotation="180"
                WidthRequest="60">

                <CollectionView.ItemTemplate>

                    <DataTemplate>

                        <Grid
                            Padding="5"
                            HeightRequest="50"
                            WidthRequest="50">

                            <Grid.RowDefinitions>

                                <RowDefinition Height="Auto" />


                            </Grid.RowDefinitions>

                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />


                            </Grid.ColumnDefinitions>
                            <!--This ImageButton contais the data of the list-->
                            <ImageButton
                                Padding="10"
                                BackgroundColor="{Binding ColorButton}"
                                Command="{Binding Source={x:Reference page}, Path=BindingContext.LaunchWeb}"
                                CommandParameter="{Binding Website}"
                                CornerRadius="70"
                                Rotation="180"
                                Source="{Binding Image}" 
                               
                                 />
                        </Grid>


                    </DataTemplate>

                </CollectionView.ItemTemplate>


            </CollectionView>
        </AbsoluteLayout>
        <ImageButton
            Margin="15"
            Padding="10"
            WidthRequest="70"
            HeightRequest="70"
            BackgroundColor="{Binding PrimaryButtonColor}"
            Command="{Binding OpenFloating}"
            CornerRadius="70"
            HorizontalOptions="End"
            Source="{Binding PrimaryImageSource}"
            VerticalOptions="EndAndExpand" />

    </StackLayout>


</ContentView>  

FloatingButton.xaml.cs:

  public partial class FloatingButton : ContentView
{


    //===============Item Source=====================
    public static readonly BindableProperty ItemSourceProperty =
            BindableProperty.Create("ItemSource", typeof(CollectionView),typeof(FloatingButton));

    public CollectionView ItemSource
    {
        get { return (CollectionView)GetValue(ItemSourceProperty); }
        set { SetValue(ItemSourceProperty, value); }
    }
    //=================================================Flo


    //===============Primary Button Image=====================
    public static readonly BindableProperty PrimaryImageSourceProperty =
            BindableProperty.Create("PrimaryImageSource", typeof(ImageSource), typeof(FloatingButton));

    public ImageSource PrimaryImageSource
    {
        get { return (ImageSource)GetValue(PrimaryImageSourceProperty); }
        set { SetValue(PrimaryImageSourceProperty, value); }
    }
    //=============================================================

    //===============Primary Button Color=====================

    public static readonly BindableProperty PrimaryButtonColorProperty =
           BindableProperty.Create("PrimaryButtonColor", typeof(Color), typeof(FloatingButton));

    public Color PrimaryButtonColor
    {
        get { return (Color)GetValue(PrimaryButtonColorProperty); }
        set { SetValue(PrimaryButtonColorProperty, value); }
    }
    //=============================================================

    public FloatingButton()
    {
        InitializeComponent();
        BindingContext = this;

     

    }
}
  

MainPage.xaml:

 <?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomControlWithList.MainPage"
             x:Name="page"
             xmlns:local="clr-namespace:CustomControlWithList">

    <local:FloatingButton
        ItemSource="ItemList"
        PrimaryImageSource="dots.png"
        PrimaryButtonColor="Green"        
        
        />

</ContentPage>  

MainPage.xaml.cs:

  public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        BindingContext = new ViewModel();
    }
}
  

ViewModel.cs:

 public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }


    public ObservableCollection<Items> ItemList { get; set; }

    private bool isVisible;

    public bool IsVisible
    {
        get => isVisible;
        set
        {
            isVisible = value;
            OnPropertyChanged();
        }
    }


    public ViewModel()
    {

        ItemList = new ObservableCollection<Items>();

        ItemList.Add(new Items { Website = "https://facebook.com", Image = "facebook.png", ColorButton = "#B52D50" });
        ItemList.Add(new Items { Website = "https://twitter.com", Image = "twitter.png", ColorButton = "#B52D50" });
        ItemList.Add(new Items { Website = "https://www.instagram.com", Image = "insta.png", ColorButton = "#B52D50" });

    }
}
  

Items.cs:

  public class Items : INotifyPropertyChanged
{

    string url, image, color;

    public string Website
    {
        get { return url; }
        set
        {
            url = value;
            OnPropertyChanged("url");

        }
    }
    public string Image
    {
        get
        {
            return image;
        }

        set
        {
            image = value;
            OnPropertyChanged("image");
        }
    }

    public string ColorButton
    {
        get
        {
            return color;
        }

        set
        {
            color = value;
            OnPropertyChanged("color");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
  

Ответ №1:

Вы могли бы установить ItemSource как связываемое свойство вместо всего CollectionView .

Кстати, поскольку вы использовали пользовательский вид, вам нужно напрямую задать путь привязки в xaml . Строка BindingContext = this; разорвет привязку между CustomView и ContentPage .

Таким образом, вы можете изменить код следующим образом

в FloatingButton.xaml

 <?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomControlWithList.FloatingButton"
             x:Name="FloatingButtonView">


    <StackLayout>

        <AbsoluteLayout>
            <CollectionView
                x:Name="listView"
                Margin="0,0,36,0"
                AbsoluteLayout.LayoutBounds="1,0,AutoSize,AutoSize"
                AbsoluteLayout.LayoutFlags="PositionProportional"
                BackgroundColor="Transparent"
                ItemsSource="{Binding Source={x:Reference FloatingButtonView}, Path=ItemSource}"
                IsVisible="{{Binding Source={x:Reference FloatingButtonView}, Path=CollectionViewVisible}"
                Rotation="180"
                WidthRequest="60">

                <CollectionView.ItemTemplate>

                    <DataTemplate>

                        <Grid
                            Padding="5"
                            HeightRequest="50"
                            WidthRequest="50">

                            <Grid.RowDefinitions>

                                <RowDefinition Height="Auto" />


                            </Grid.RowDefinitions>

                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />


                            </Grid.ColumnDefinitions>
                            <!--This ImageButton contais the data of the list-->
                            <ImageButton
                                Padding="10"
                                BackgroundColor="{Binding ColorButton}"
                                Command="{{Binding Source={x:Reference FloatingButtonView}, Path=LaunchWeb}"
                                CommandParameter="{{Binding Source={x:Reference FloatingButtonView}, Path=Website}"
                                CornerRadius="70"
                                Rotation="180"
                                Source="{Binding Image}" 
                               
                                 />
                        </Grid>


                    </DataTemplate>

                </CollectionView.ItemTemplate>


            </CollectionView>
        </AbsoluteLayout>
        <ImageButton
            Margin="15"
            Padding="10"
            WidthRequest="70"
            HeightRequest="70"
            BackgroundColor="{{Binding Source={x:Reference FloatingButtonView}, Path=PrimaryButtonColor}"
            Command="{Binding Source={x:Reference FloatingButtonView}, Path=OpenFloating}"
            CornerRadius="70"
            HorizontalOptions="End"
            Source="{{Binding Source={x:Reference FloatingButtonView}, Path=PrimaryImageSource}"
            VerticalOptions="EndAndExpand" />

    </StackLayout>


</ContentView>
  
 public FloatingButton()
{
   InitializeComponent();
   //   BindingContext = this;

}

//...

//===============Item Source=====================
        public static readonly BindableProperty ItemSourceProperty =
                BindableProperty.Create("ItemSource", typeof(ObservableCollection<Items>), typeof(FloatingButton));

        public ObservableCollection<Items> ItemSource
        {
            get { return (ObservableCollection<>)GetValue(ItemSourceProperty); }
            set { SetValue(ItemSourceProperty, value); }
        }


        public static readonly BindableProperty CollectionViewVisibleProperty =
                BindableProperty.Create("PrimaryImageSource", typeof(bool), typeof(FloatingButton),false);

        public bool CollectionViewVisible
        {
            get { return (bool)GetValue(CollectionViewVisibleProperty); }
            set { SetValue(CollectionViewVisibleProperty, value); }
        }

public static readonly BindableProperty LaunchWebProperty =
            BindableProperty.Create(nameof(LaunchWeb), typeof(ICommand), typeof(FloatingButton));

        public ICommand LaunchWeb
        {
            get => (ICommand)GetValue(LaunchWebProperty );
            set => SetValue(LaunchWebProperty , value);
        }

        public static BindableProperty WebsiteProperty =
            BindableProperty.Create(nameof(Website), typeof(object), typeof(FloatingButton));

        public object Website
        {
            get => (object)GetValue(WebsiteProperty );
            set => SetValue(WebsiteProperty , value);
        }

     //other bindable property like this

  

в ContentPage

Теперь вы можете установить привязку следующим образом

  <local:FloatingButton
        ItemSource="{Binging ItemList}"
        CollectionViewVisible = "{Binding IsVisible}"
        PrimaryImageSource="dots.png"
        PrimaryButtonColor="Green"        
        
        />