SfPopuplayout relative position changes on SfAccordion filter and shows in two positions

Hi Team,


I have a SfPopupLayout in SfAccordian Header. The Relative Position of a SfPopupLayout in "AlignBottomRight". Intially it shows up in bottomRight but when i filter the accordion header and update 

BindableLayout.SetItemsSource(accordian, data),

 the relative position changes to "AlignTop" and it appears in both positions.


Regards,

Pradeepa 



13 Replies

SV Suja Venkatesan Syncfusion Team April 27, 2022 01:53 PM UTC

Hi Pradeepa,


We'd like to inform you that we have no idea how you use SfPopupLayout in SfAccordion or how you open SfPopup in your application. Can you please share more details regarding the reported issue with code snippets related to SfAccordion and SfPopup with illustration video or image? if possible please share the simple sample to replicate the reported scenario on our end. It will be more helpful for us to provide the prompt solution at earlier.


Regards,

Suja



PR Pradeepa April 27, 2022 02:55 PM UTC

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"

             xmlns:local="clr-namespace:GettingStarted"

             x:Class="GettingStarted.MainPage"

             xmlns:sfListView="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms"

             xmlns:sfPopup="clr-namespace:Syncfusion.XForms.PopupLayout;assembly=Syncfusion.SfPopupLayout.XForms"

             xmlns:syncfusion="clr-namespace:Syncfusion.XForms.Accordion;assembly=Syncfusion.Expander.XForms">

    <ContentPage.BindingContext>

        <local:ContactsViewModel x:Name="viewModel"/>

    </ContentPage.BindingContext>

    <ContentPage.Content>

        <StackLayout>

            <SearchBar TextChanged="SearchBar_TextChanged">

        </SearchBar>

            <syncfusion:SfAccordion x:Name="Accordion" BindableLayout.ItemsSource="{Binding Path=AccordionItem}"

                    AutoScrollPosition="None"

                    AutomationId="RelatedRecordAccordion"

                    ExpandMode="SingleOrNone"

                    HeaderIconPosition="None"

                    DynamicSizeMode="None"

                    VerticalOptions="FillAndExpand"

                    HorizontalOptions="FillAndExpand"

                    AnimationEasing="None"

                    IsVisible="{Binding Path=HasRelatedData}"

                    Margin="10, 10, 10, 0">

            <BindableLayout.ItemTemplate>

                    <DataTemplate>

                  <syncfusion:AccordionItem>

                    <syncfusion:AccordionItem.Header>

                        <Grid Padding="10,0,0,10">

                                <Label TextColor="#495F6E" Grid.Column="0" Text="{Binding HeaderText}" HeightRequest="50" VerticalTextAlignment="Center"/>

                                    <sfPopup:SfPopupLayout x:Name="popupLayout" Grid.Column="1" IsOpen="{Binding isOpen}" RelativePosition="AlignBottomRight">

                                <sfPopup:SfPopupLayout.RelativeView>

                                    <x:Reference Name="ClickButton" />

                                </sfPopup:SfPopupLayout.RelativeView>

                                        <sfPopup:SfPopupLayout.PopupView

                                            AutoSizeMode="None"

                                                            ShowHeader="False"

                                                            ShowFooter="False"

                                                            ShowCloseButton="False"

                                                            HeightRequest="290"

                                                            WidthRequest="250"

                                                            AnimationMode="None">

                                    <sfPopup:PopupView HeaderTitle="ListView" HeightRequest ="200" ShowCloseButton="False"

                                                       ShowFooter="False">

                                        <sfPopup:PopupView.ContentTemplate>

                                            <DataTemplate>

                                                        <sfListView:SfListView x:Name="listView" ItemSpacing="5" WidthRequest="350"

                          ItemsSource="{Binding Items}" >

                                        <sfListView:SfListView.ItemTemplate>

                                             <DataTemplate>

                                                 <ViewCell>

                                                     <ViewCell.View>

                                                           <StackLayout Orientation="Horizontal">

                                                                <Label Grid.Column="1"

                                                                    HorizontalTextAlignment="Center"

                                                                    LineBreakMode="NoWrap"

                                                                    Text="{Binding ContactName}"

                                                                    FontSize="Medium" />

                                                           </StackLayout>

                                                                </ViewCell.View>

                                                            </ViewCell>

                                                        </DataTemplate>

                                                    </sfListView:SfListView.ItemTemplate>

                                                </sfListView:SfListView>

                                            </DataTemplate>

                                        </sfPopup:PopupView.ContentTemplate>

                                    </sfPopup:PopupView>

                                </sfPopup:SfPopupLayout.PopupView>

                                <sfPopup:SfPopupLayout.Content>

                                    <StackLayout>

                                                <Button Text="Click to show popup" x:Name="ClickButton" >

                                                    <Button.Behaviors>

                                                        <local:EventToCommandBehavior EventName="Clicked" Command="{Binding Path=ItemTapped}" />

                                                    </Button.Behaviors>

                                                </Button>

                                    </StackLayout>

                                </sfPopup:SfPopupLayout.Content>

                            </sfPopup:SfPopupLayout>

                        </Grid>

                    </syncfusion:AccordionItem.Header>


                    <syncfusion:AccordionItem.Content>

                        <Grid Padding="10,0,0,10" BackgroundColor="#FFFFFF">

                            <Label TextColor="#303030" Text="11.03 AM, 15 January 2019" HeightRequest="50" VerticalTextAlignment="Center"/>


                        </Grid>

                    </syncfusion:AccordionItem.Content>

                        </syncfusion:AccordionItem>

                    </DataTemplate>

            </BindableLayout.ItemTemplate>

        </syncfusion:SfAccordion>

        </StackLayout>

    </ContentPage.Content>

</ContentPage>


MainPage.xaml.cs

using Syncfusion.XForms.Accordion;

using Xamarin.Forms;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using Syncfusion.ListView.XForms;

using Syncfusion.XForms.PopupLayout;


namespace GettingStarted

{

public partial class MainPage : ContentPage

{

        public MainPage()

{

InitializeComponent();

        }



        private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)

        {

            //this works fine only if we create a new instance to a viewmodel- but that is not the proper way as all viewmodel object will be reset

            // var viewModel = new ContactsViewModel();

            var accordionItems = viewModel.AccordionItem;

            if (string.IsNullOrEmpty(e.NewTextValue))

            {

                BindableLayout.SetItemsSource(Accordion, accordionItems);

                return;

            }

            if (!string.IsNullOrEmpty(e.NewTextValue) && e.NewTextValue.Length <4 )

            {


                return;

            }

            var filteredSource = accordionItems.Where(x => (x.HeaderText.ToLower()).StartsWith(e.NewTextValue.ToLower())).ToList();

            BindableLayout.SetItemsSource(Accordion, filteredSource);

        }

    }

}

ContactsViewModel.cs


using Syncfusion.XForms.Accordion;

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Linq;

using System.Runtime.CompilerServices;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Input;

using Xamarin.Forms;


namespace GettingStarted

{

    public class ContactsViewModel :BaseViewModel

    {



        public ContactsViewModel()

        {

            AccordionItems accordion = new AccordionItems();

            AccordionItems accordion1 = new AccordionItems();

            List<AccordionItems> items = new List<AccordionItems>();

            OnSearchTextChangedCommand = new Command((obj) => OnSearch(obj));

            accordion.HeaderText = "Test";


            accordion.Items.Add(new Contacts(){ ContactName="accordion1Data1" });

            accordion.Items.Add(new Contacts(){ ContactName = "accordion1Data2" });

            accordion.Items.Add(new Contacts(){ ContactName = "accordion1Data3" });

            items.Add(accordion);


            accordion1.HeaderText = "Test1";


            accordion1.Items.Add(new Contacts() { ContactName = "accordion2Data1" });

            accordion1.Items.Add(new Contacts() { ContactName = "accordion2Data2" });

            accordion1.Items.Add(new Contacts() { ContactName = "accordion2Data3"});

            items.Add(accordion1);

            AccordionItem = items;

        }

        private string _searchTerm;

        public string SearchTerm

        {

            get => _searchTerm;

            set => RaiseAndUpdate(ref _searchTerm, value);

        }

        public ICommand OnSearchTextChangedCommand { get; private set; }

        public void OnSearch(object obj,string SearchTerm=null)

        {

           SfAccordion Accordion = obj as SfAccordion;


            var accordionItems =AccordionItem;

            if (string.IsNullOrEmpty(SearchTerm))

            {

                BindableLayout.SetItemsSource(Accordion, accordionItems);

                return;

            }

            if (!string.IsNullOrEmpty(SearchTerm) && SearchTerm.Length < 4)

            {


                return;

            }

            var filteredSource = accordionItems.Where(x => (x.HeaderText.ToLower()).StartsWith(SearchTerm.ToLower())).ToList();

            BindableLayout.SetItemsSource(Accordion, filteredSource);

        }


        private List<AccordionItems> accordionItem = new List<AccordionItems>();

        public List<AccordionItems> AccordionItem

        {

            get => accordionItem;

            set => RaiseAndUpdate(ref accordionItem, value);

        }



    }



    public class AccordionItems :BaseViewModel

    {

        private string headerText = "";


        public ICommand ItemTapped { get; set; }

        public AccordionItems()

        {

            ItemTapped = new Command<EventArgs>((args) => isOpenButton_Clicked(args));

        }



        public string HeaderText

        {

            get => headerText;

            set => RaiseAndUpdate(ref headerText, value);

        }

        private List<Contacts> contacts = new List<Contacts>();

        public List<Contacts> Items

        {

            get => contacts;

            set => RaiseAndUpdate(ref contacts, value);

        }

        private bool _isOpen;


        public bool isOpen

        {

            get => _isOpen;

            set => RaiseAndUpdate(ref _isOpen, value);

        }

        private void isOpenButton_Clicked(EventArgs args)

        {

            isOpen = !isOpen;

        }

    }

   public class Contacts

    {

        public string ContactName { get; set; }

        private bool isOpen { get; set; }


    }


    public class BaseViewModel : INotifyPropertyChanged

    {

        public event PropertyChangedEventHandler PropertyChanged;


        protected bool RaiseAndUpdate<T>(ref T field, T value, [CallerMemberName] string propertyName = null)

        {

            if (EqualityComparer<T>.Default.Equals(field, value))

            {

                return false;

            }


            field = value;

            Raise(propertyName);


            return true;

        }


        protected void Raise(string propertyName)

        {

            if (!string.IsNullOrEmpty(propertyName))

            {

                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

            }

        }

    }

}




SV Suja Venkatesan Syncfusion Team April 28, 2022 02:33 PM UTC

Hi Pradeepa,


We are able to replicate the reported issue on our end. Currently, we are validating the reported issue on our end. We are in need of two more business days to validate this properly. We will update you with further details on or before May 2, 2022. We appreciate patience and understanding.


Regards,

Suja



SV Suja Venkatesan Syncfusion Team May 2, 2022 03:16 PM UTC

Hi Pradeepa,


We would like to inform you that the reported issue occurs due to setting itemsource for bindableLayout once again in SearchTextChanged event, you can resolve the reported issue by filtering data as like below code snippet.


Code snippet:

private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)

        {

            var accordionItems = viewModel.AccordionItem;

           var accord = (accordionItems.Where(x => (x.HeaderText.ToLower()).StartsWith(e.NewTextValue.ToLower())));

            for (int i = viewModel.AccordionItem.Count - 1; i >= 0; i--)

            {

                var item = viewModel.AccordionItem[i];

                if (!accord.Contains(item))

                {

                    viewModel.AccordionItem.Remove(item);

                }

            }

            foreach (var item in accord)

            {

                if (!viewModel.AccordionItem.Contains(item))

                {

                    viewModel.AccordionItem.Add(item);

                }

            }

        }

 


Please use type of ViewModel.AccordionItem as ObservableCollection instead of List type. We have attached a modified sample for your reference. Please let us know if you need any further assistance.


Regards,

Suja



PR Pradeepa May 4, 2022 06:38 AM UTC

Hi  Suja,

The above method wont work to filter the accordion data as it reset the Accordion Itemsource

(viewModel.AccordionItem) after a Search and will loose the original accordion data after clearing the search text.






SV Suja Venkatesan Syncfusion Team May 5, 2022 02:06 PM UTC

Hi Pradeepa,


Currently, we are validating the reported Scenario on our end. We are in need of two more business days to validate this properly. We will update you with further details on or before May 9, 2022. We appreciate patience and understanding.


Regards,

Suja




SV Suja Venkatesan Syncfusion Team May 9, 2022 02:14 PM UTC

Hi Pradeepa,


Currently, we are validating the reported issue on our end. We will update you with the details on or before May 11, 2022. We appreciate your patience and understanding.


Regards,

Suja



SV Suja Venkatesan Syncfusion Team May 11, 2022 02:27 PM UTC

Hi Pradeepa,


We deeply regret for the inconvenience caused, for the scenario “Original accordion data missed after clearing the search text”, You can solve the problem by keeping a copy of the bindable collection and updating the binded collection once the search text is null, as like below code snippet.


Code Snippet:

//MainPage.Xaml.cs

private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)

{

   var accordionItems = viewModel.AccordionItem;

   if (string.IsNullOrEmpty(e.NewTextValue))

   {

      //To restore the original data of binded collection

      viewModel.AccordionItem = viewModel.AccordionItem_Copy;

      return;

    }

var accord = (accordionItems.Where(x => (x.HeaderText.ToLower()).StartsWith(e.NewTextValue.ToLower())));

}


We have attached a runnable sample for your reference. Please have a look at this sample and let us know if you have any concern in it.


Regards,

Suja


Attachment: T174639_cbf2e417.zip


PR Pradeepa May 12, 2022 12:32 PM UTC

Hi Team, 


I could say this is a workaround for the actual issue. On updating itemsource for the accordian (bindableLayout) , the sfpopup should not get affected ,Could you please check and fix that part?



Regards,

Pradeepa



SV Suja Venkatesan Syncfusion Team May 13, 2022 01:56 PM UTC

Hi Pradeepa,


We have logged the issue report for ” SfPopupView in SfAccordion header opened twice when setting bindablelayout.Itemsource in runtime” We will fix the issue and include the fix in our next Weekly Nuget release update which is planned to roll out on June 7, 2022. We appreciate your patience until then.


You can track the status of this report through the following feedback link,


Note: The feedback link provided is private, you need to login to view this feedback.

https://www.syncfusion.com/feedback/34906/sfpopupview-in-sfaccordion-header-opened-twice-when-setting-bindablelayout


Regards,

Suja




SV Suja Venkatesan Syncfusion Team June 8, 2022 04:46 PM UTC

Hi Pradeepa,


We regret to let you know that, as we promised we are unable to include the fix. We need some more time to this fix. We will include the fix in our 2022 Volume 2 main release which is planned to release on End of June. We will let you know once it gets released with the fix. We appreciate your patience until then.


Regards,

Suja



SV Suja Venkatesan Syncfusion Team July 1, 2022 01:35 PM UTC

Hi Pradeepa,


We regret to let you know that, as we promised we are unable to include the fix. We need some more time to ensure all possible test cases with this fix. We will include the fix in our upcoming weekly nuget which is scheduled to release on July 12, 2022. We will let you know once it gets released with the fix. We appreciate your patience until then.


Regards,

Suja




SV Suja Venkatesan Syncfusion Team July 12, 2022 07:32 AM UTC

Hi Pradeepa,


We regret for the inconvenience caused. We would like to let you know that you can resolve the reported scenario by resetting the removed item’s BindingContext to null in sample level. When updating the ItemsSource at run time with the old model data, the BindingContext of the removed item is not reset to null. And the removed item’s BindingContext is maintained as duplicate. When changing the changing the IsOpen property of the popuplayout, duplicate popup was opened. The reported scenario can also be reproduced using framework controls. Please find the framework bug report


Bug report: https://github.com/xamarin/Xamarin.Forms/issues/12202


As a result, we kindly suggested that the removed item's BindingContext be reset to null in the Accordion PropertyChanged event, as shown in the code snippet below.


Code Snippet:

XAML:

            <syncfusion:SfAccordion x:Name="Accordion" BindableLayout.ItemsSource="{Binding Path=AccordionItem}"

                    AutoScrollPosition="None"

                    PropertyChanged="Accordion_PropertyChanged"

                    AutomationId="RelatedRecordAccordion"

                    ExpandMode="SingleOrNone"

                    HeaderIconPosition="None"

                    DynamicSizeMode="None"

                    VerticalOptions="FillAndExpand"

                    HorizontalOptions="FillAndExpand"

                    AnimationEasing="None"

                    IsVisible="{Binding Path=HasRelatedData}"

                    Margin="10, 10, 10, 0">


C#:

       private void Accordion_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)

        {

            if (e.PropertyName == "ItemsSource")

            {

                var accordion = sender as SfAccordion;

                var items = accordion.Items;

                if (items.Count > 0)

                {

                    foreach (var accordionItem in items)

                    {

                        accordionItem.BindingContext = null;

                    }

                }

            }

        }


We have attached a modified sample for your reference. Please let us know if you need any further assistance.


Regards,

Suja


Attachment: customersample_248b0058.zip

Loader.
Up arrow icon