This is a migrated thread and some comments may be shown as answers.

Different VisualItem depends on DataBoundItem

3 Answers 129 Views
ListControl
This is a migrated thread and some comments may be shown as answers.
Pavel
Top achievements
Rank 1
Pavel asked on 03 Mar 2021, 08:28 AM
Hello!
I'm implementing a notification list where is possible to have several different layouts depends on the bound item's type. The problem is RadListControl attach incompatible DataItem to VisualItem.
In other words, is it possible to have something similar to Android's RecyclerView where depends on an item type you can have a different layout?

001.internal class NotificationA : INotification {
002.     public string Name { get; set; }
003.     public string Type => nameof(NotificationA);
004.}
005. 
006.internal class NotificationB : INotification {
007.    public int Degree { get; set; }
008.    public string Type => nameof(NotificationB);
009.}
010. 
011.internal class NotificationAListItem : RadListVisualItem {
012.        private LightVisualElement notificationTitleElement;
013.        private StackLayoutPanel stackLayout;
014. 
015.        protected override void CreateChildElements()
016.        {
017.            base.CreateChildElements();
018. 
019.            stackLayout = new StackLayoutPanel();
020.            stackLayout.Orientation = System.Windows.Forms.Orientation.Vertical;
021. 
022.            notificationTitleElement = new LightVisualElement();
023.            notificationTitleElement.TextAlignment = ContentAlignment.MiddleLeft;
024.            notificationTitleElement.Margin = new Padding(10);
025.            notificationTitleElement.ForeColor = Color.Black;
026.            stackLayout.Children.Add(notificationTitleElement);
027. 
028.            this.Children.Add(stackLayout);
029.        }
030. 
031.        public override void Synchronize()
032.        {
033.            base.Synchronize();
034.            Text = string.Empty;
035.            if (Data.DataBoundItem is not NotificationA n) return;
036.            notificationTitleElement.Text = Convert.ToString(n.Name);
037.        }
038. }
039. 
040.internal class NotificationBListItem : RadListVisualItem
041.    {
042.        private LightVisualElement notificationTitleElement;
043.        private StackLayoutPanel stackLayout;
044. 
045.        protected override void CreateChildElements()
046.        {
047.            base.CreateChildElements();
048. 
049.            stackLayout = new StackLayoutPanel();
050.            stackLayout.Orientation = Orientation.Vertical;
051. 
052. 
053.            notificationTitleElement = new LightVisualElement();
054.            notificationTitleElement.TextAlignment = ContentAlignment.MiddleLeft;
055.            notificationTitleElement.Margin = new Padding(10);
056.            notificationTitleElement.ForeColor = Color.Black;
057.            stackLayout.Children.Add(notificationTitleElement);
058. 
059.            Children.Add(stackLayout);
060. 
061.            Padding = new Padding(5);
062.            Shape = new RoundRectShape(3);
063.            BorderColor = Color.FromArgb(255, 110, 153, 210);
064.            BorderGradientStyle = GradientStyles.Solid;
065.            DrawBorder = true;
066.            DrawFill = true;
067.            BackColor = Color.FromArgb(255, 230, 238, 254);
068.            GradientStyle = GradientStyles.Solid;
069.        }
070. 
071.        public override void Synchronize()
072.        {
073.            base.Synchronize();
074.            Text = string.Empty;
075.            if (Data.DataBoundItem is not NotificationB n) return;
076.            notificationTitleElement.Text = Convert.ToString(n.Degree);
077.        }
078.}
079. 
080.public partial class TestForm : RadForm {
081.        public TestForm() {
082.            InitializeComponent();
083.            InitializeViewAppearance();
084.        }
085. 
086.        private void InitializeViewAppearance() {
087.            var notifications = new List<INotification> {
088.                new NotificationA {Name = "Foo"},
089.                new NotificationA {Name = "Bar"},
090.                new NotificationB { Degree = 180 }
091.            };
092.            for (var i = 0; i < 100000; i++) {
093.                notifications.Add(new NotificationA { Name = $"test item {i}" });
094.            }
095.            lcNotifications.CreatingVisualListItem += OnNotificationItemCreating;
096.            lcNotifications.DataSource = notifications;
097.        }
098. 
099.        private void OnNotificationItemCreating(object sender, CreatingVisualListItemEventArgs args)
100.        {
101.            args.VisualItem = args.DataItem.DataBoundItem switch {
102.                NotificationA _ => new NotificationAListItem(),
103.                NotificationB _ => new NotificationBListItem(),
104.                _ => args.VisualItem
105.            };
106.        }
107.    }

3 Answers, 1 is accepted

Sort by
0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 03 Mar 2021, 10:47 AM

Hello, Pavel,

According to the provided information, it seems that you need to display different elements in the RadListControl's visual items depending on a value in the DataBoundItem

The possible solution that I can suggest is to create one common RadListVisualItem and add all the elements that you will need to show in the visual item. However, in the Synchronize method you will manage the Visibility of each element considering your custom condition.

Following the provided code snippet, I have prepared a sample that illustrates the described approach: 

        public RadForm1()
        {
            InitializeComponent();
            InitializeViewAppearance();
            this.radListControl1.ItemHeight = 40;
        }
        private void InitializeViewAppearance()
        {
            var notifications = new List<Notification> {
                 new NotificationA {Name = "Foo"},
                 new NotificationA {Name = "Bar"},
                 new NotificationB { Degree = 180 }
             };
            for (var i = 0; i < 100000; i++)
            {
                notifications.Add(new NotificationA { Name = $"test item {i}" });
            }
            radListControl1.CreatingVisualListItem += OnNotificationItemCreating;
            radListControl1.DataSource = notifications;
        }
        private void OnNotificationItemCreating(object sender, CreatingVisualListItemEventArgs args)
        {
            args.VisualItem = new NotificationVisualItem();
        }

        public class NotificationVisualItem : RadListVisualItem
        {
            private LightVisualElement notificationATitleElement;
            private LightVisualElement notificationBTitleElement;
            private StackLayoutPanel stackLayout;

            protected override void CreateChildElements()
            {
                base.CreateChildElements();

                stackLayout = new StackLayoutPanel();
                stackLayout.Orientation = System.Windows.Forms.Orientation.Vertical;

                notificationATitleElement = new LightVisualElement();
                notificationATitleElement.TextAlignment = ContentAlignment.MiddleLeft;
                notificationATitleElement.Margin = new Padding(10);
                notificationATitleElement.ForeColor = Color.Red;

                notificationBTitleElement = new LightVisualElement();
                notificationBTitleElement.TextAlignment = ContentAlignment.MiddleLeft;
                notificationBTitleElement.Margin = new Padding(10);
                notificationBTitleElement.ForeColor = Color.Blue;

                stackLayout.Children.Add(notificationATitleElement);
                stackLayout.Children.Add(notificationBTitleElement); 

                Padding = new Padding(5);
                Shape = new RoundRectShape(3);
                BorderColor = Color.FromArgb(255, 110, 153, 210);
                BorderGradientStyle = GradientStyles.Solid;
                DrawBorder = true;
                DrawFill = true;
                BackColor = Color.FromArgb(255, 230, 238, 254);
                GradientStyle = GradientStyles.Solid;

                this.Children.Add(stackLayout);
            }

            public override void Synchronize()
            {
                base.Synchronize();
                this.DrawText = false;
                NotificationA dataItemA = this.Data.DataBoundItem as NotificationA;
                NotificationB dataItemB = this.Data.DataBoundItem as NotificationB;
                if (dataItemA != null)
                {
                    notificationATitleElement.Visibility = ElementVisibility.Visible;
                    notificationBTitleElement.Visibility = ElementVisibility.Collapsed;
                    notificationATitleElement.Text = dataItemA.Name;
                }
                else if (dataItemB != null)
                {
                    notificationATitleElement.Visibility = ElementVisibility.Collapsed;
                    notificationBTitleElement.Visibility = ElementVisibility.Visible;
                    notificationBTitleElement.Text = dataItemB.Degree.ToString(); ;
                }
            }
        } 

        internal class Notification
        {
            public int Id { get; set; }
        }
        internal class NotificationA : Notification
        {
            public string Name { get; set; }
            public string Type => nameof(NotificationA);
        }

        internal class NotificationB : Notification
        {
            public int Degree { get; set; }
            public string Type => nameof(NotificationB);
        } 

Note that this is just a sample approach and it may not cover all possible cases. Feel free to modify and extend it in a way which suits your requirements best.

I hope this information helps. If you need any further assistance please don't hesitate to contact me. 

Regards,
Dess | Tech Support Engineer, Sr.
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
Pavel
Top achievements
Rank 1
answered on 04 Mar 2021, 12:49 PM
Sorry for being not very specific. Yes, it is exactly what I needed. Thank you!
I use RadListVisualItem as hosting object for different RadElements are stored in IDicitonary<Type, RadElement>. Then during a call of Synchronize method, I look for a specific RadElement, pass INotification data object and change element to visible.
I attach an archive with an example for anyone who may stumble across a similar use case.
https://drive.google.com/file/d/1RLyoGPTko7h2Vhzk2hXSgPNc_fqAozD4
0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 05 Mar 2021, 07:09 AM
Hello, Pavel,

I have reviewed the provided sample project. I am really glad that you succeeded to adopt the suggested solution in your application and now you can use different design in the items according to the associated data item. Thank you for sharing your final implementation with the community.  

Should you have further questions please let me know.

Regards,
Dess | Tech Support Engineer, Sr.
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Tags
ListControl
Asked by
Pavel
Top achievements
Rank 1
Answers by
Dess | Tech Support Engineer, Principal
Telerik team
Pavel
Top achievements
Rank 1
Share this question
or