Rg.Plugins.Popup icon indicating copy to clipboard operation
Rg.Plugins.Popup copied to clipboard

BindingContext not working if Content is in a separate class

Open denmusic1992 opened this issue 6 years ago • 7 comments
trafficstars

Popup Ver. = 1.1.5.180

Hello! Let me explain the issue: I have a class called CommonPopupPage with empty content for using it anywhere and for not to copy/paste xaml code for init the page.

xaml looks like so:

<?xml version="1.0" encoding="utf-8" ?>
<pages:PopupPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup"
                 xmlns:animations="clr-namespace:Rg.Plugins.Popup.Animations;assembly=Rg.Plugins.Popup"
                 x:Class="CommonClassesLibrary.CommonPopupPage"
                 CloseWhenBackgroundIsClicked="True">
    <pages:PopupPage.Animation>
        <animations:ScaleAnimation
            PositionIn="Center"
            PositionOut="Center"
            ScaleIn="1.2"
            ScaleOut="0.8"
            DurationIn="400"
            DurationOut="300"
            EasingIn="SinOut"
            EasingOut="SinIn"
            HasBackgroundAnimation="True"/>
    </pages:PopupPage.Animation>
    <Frame HorizontalOptions="Center"
           VerticalOptions="Center"
           CornerRadius="5"
           Margin="40"
           Padding="0">
        <StackLayout Orientation="Vertical" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" BackgroundColor="White">
            <AbsoluteLayout HorizontalOptions="Fill" VerticalOptions="Fill" BackgroundColor="Accent">
                <Label VerticalOptions="Fill" HorizontalOptions="Fill" HorizontalTextAlignment="Center" Margin="50, 0, 50, 0" 
                       VerticalTextAlignment="Center" x:Name="HeaderName" Style="{StaticResource LabelSmallWhite}" AbsoluteLayout.LayoutBounds="0.5, 0.5, 1, 1"
                       AbsoluteLayout.LayoutFlags="All" x:FieldModifier="public" />
                <Button VerticalOptions="Center" HorizontalOptions="Center" WidthRequest="25"
                        HeightRequest="25" Clicked="ButtonCloseClicked" Image="close_button_black.png" Style="{StaticResource ButtonStandardWhite}"
                        AbsoluteLayout.LayoutBounds="1, 0, 50, 50" AbsoluteLayout.LayoutFlags="PositionProportional" />
            </AbsoluteLayout>
            <ContentView x:Name="CommonContent" x:FieldModifier="public" VerticalOptions="Center" HorizontalOptions="Center" />
        </StackLayout>
    </Frame>
</pages:PopupPage>

So I use it for my ListViewPopupPage, that is a ContentView:

<?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:controls="clr-namespace:Plugin.InputKit.Shared.Controls;assembly=Plugin.InputKit"
             x:Class="ISSO_I.PopupTypes.MultiselectListView">
    <ContentView.Content>
        <StackLayout>
            <ListView RowHeight="70" Margin="5" ItemsSource="{Binding Items}" CachingStrategy="RecycleElement">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout Orientation="Horizontal">
                                <controls:CheckBox IsChecked="{Binding IsChecked}" LabelPosition="After" Margin="10"
                                                   Type="Material" Text="{Binding Body}" TextColor="Black" />
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            <BoxView Color="Accent" HeightRequest="1" />
            <controls:CheckBox IsChecked="{Binding Path=AllChecked}" LabelPosition="After" Margin="10" Type="Material"
                               Text="(Выбрать все)" TextColor="Black" />
            <Button Style="{StaticResource ButtonStandard}" Margin="10" Text="Применить" Clicked="ButtonConfirmClicked"/>
        </StackLayout>
    </ContentView.Content>
</ContentView>

For this class data binding not working at all. But if I change it's type to, e.g. ContentPage, data binding works! What's wrong with my approach? Is it a bug?

denmusic1992 avatar May 15 '19 05:05 denmusic1992

@denmusic1992 How do you apply BindingContext?

rotorgames avatar May 15 '19 05:05 rotorgames

@rotorgames Will post my code of model, viewmodel and view.

MultiselectListView.xaml.cs:

public partial class MultiselectListView
	{

		public MultiselectListViewModel Vm;

		public event EventHandler ApplyConstrs;

		/// <summary>
		/// Для заголовка окна
		/// </summary>
		public const string Header = "Выбранные номера конструкций";

		public MultiselectListView (ObservableCollection<MultiselectItem> items)
		{
			InitializeComponent();
			//MultiListView.ItemsSource = _vm.Items;
			Vm = new MultiselectListViewModel(items);
			BindingContext = Vm;
		}
		...
	}

model.cs:

public class MultiselectListViewModel : INotifyPropertyChanged
    {
		/// <summary>
		/// Номера конструкций
		/// </summary>
	    private ObservableCollection<MultiselectItem> _items;
	    public ObservableCollection<MultiselectItem> Items
	    {
		    get => _items;
		    set
		    {
			    if (_items == value) return;
			    _items = value;
				OnPropertyChanged(nameof(Items));
		    }
	    }

	    private bool _allChecked;
	    public bool AllChecked
	    {
		    get => _allChecked;
		    set
		    {
			    if (_allChecked == value) return;
			    _allChecked = value;
				OnPropertyChanged(nameof(AllChecked));
				// Меняем все галочки
			    foreach (var item in Items)
			    {
				    item.IsChecked = _allChecked;
			    }
		    }
	    }

	    public MultiselectListViewModel(ObservableCollection<MultiselectItem> items)
	    {
		    Items = items;
	    }

	    #region INotify Staff

	    public event PropertyChangedEventHandler PropertyChanged;

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

	    #endregion
	    
    }

and model.cs:

public class MultiselectItem : INotifyPropertyChanged
    {

	    /// <summary>
	    /// Признак выбранного элемента
	    /// </summary>
	    private bool _isChecked;

	    public bool IsChecked
	    {
		    get => _isChecked;
		    set
		    {
				if(_isChecked == value) return;
			    _isChecked = value;
				OnPropertyChanged(nameof(IsChecked));
		    }
	    }

	    /// <summary>
	    /// Текст элемента
	    /// </summary>
	    public string Body { get; set; }

	    public event PropertyChangedEventHandler PropertyChanged;

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

denmusic1992 avatar May 15 '19 06:05 denmusic1992

@denmusic1992 I can't see anything wrong that can refer to this plugin. I think the problem in your code but if you still think that the problem is in the plugin, please, create a simple project where I can replicate this issue. Thanks.

rotorgames avatar May 15 '19 13:05 rotorgames

I am also able to replicate this issue, I'm using Fody.PropertyChanged for the PropertyChanged code. I've tested the code in a normal view and it works, but in a PopupPage it doesn't work.

ybadragon avatar May 21 '19 13:05 ybadragon

Hi @rotorgames ! Sorry for a very late answer, just now I've had some free time to create sample code. Here is zip archive with it inside: ListTestApp.zip

denmusic1992 avatar May 24 '19 03:05 denmusic1992

your problem is probably with contentview that you are bindingcontext on contentview. if you try to set bindincontext of popuppage, it should be working.

EmilAlipiev avatar May 28 '19 11:05 EmilAlipiev

@denmusic1992 Did you solve this issue or still get?

rotorgames avatar Jul 23 '19 09:07 rotorgames