ListView IconView Custom Item with buttons and text

2 Answers 1475 Views
ListView
David
Top achievements
Rank 1
Iron
Iron
Iron
David asked on 19 May 2022, 03:36 AM

Hi,

I've followed the instructions for creating a custom visual Item, but I need some direction on how to make that example more useful and attractive.

What I need is the item image shown (a thumbnail image, it's an image gallery listview), and under that I need two buttons with transparent png images, side by side.  32x32 icons (and the listview item itself is big, like 180x180.) Under the icons I need the Text of the bound item with 18pt font.

I've tried adding panels with the buttons, adding a lable element with custom font size... it's not really coming along very nicely and I feel like I'm just stumbling along and one day might get it all looking good haha

I added event handlers for the buttons inside my custom item class, is that the righ way to do it?

delBtnElem.Click += delBtnElem_Click;

But now the top-level click event on the item is not firing. Is my panel overlaying it all? I set an huge top margin to try to align the buttons under the Icon View image.

 

So maybe you can help me figure out the best way to lay it out?

 

Thank You!

-David

 

 

Here is the code in my Custom Item class (GalleryItemView):  

public class GalleryItemView : IconListViewVisualItem
    { ...

 

 

protected override void CreateChildElements() { base.CreateChildElements(); stack.Orientation = Orientation.Vertical; btnPanel.Margin = new Padding(0, 80, 0, 0); printBtnElem.Image = Image.FromFile(@"..\..\Resources\print-icon.png"); printBtnElem.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; printBtnElem.Click += printBtnElem_Click; delBtnElem.Image = Image.FromFile(@"..\..\Resources\delete-icon.png"); delBtnElem.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; delBtnElem.Click += delBtnElem_Click; titleElem.Margin = new Padding(8); titleElem.CustomFontSize = 18F; btnPanel.Children.Add(printBtnElem); btnPanel.Children.Add(delBtnElem); stack.Children.Add(btnPanel); stack.Children.Add(titleElem); this.Children.Add(stack); }


 

 

 

Here is some code form my Form:



 private void radListViewGallery_VisualItemCreating(object sender, ListViewVisualItemCreatingEventArgs e)
        {
            if (this.radListViewGallery.ViewType == ListViewType.IconsView)
            {
                e.VisualItem = new GalleryItemView();
            }
        }

void radListViewGallery_VisualItemFormatting(object sender, Telerik.WinControls.UI.ListViewVisualItemEventArgs e)
        {
            e.VisualItem.DrawText = false;
            e.VisualItem.ImageLayout = ImageLayout.Zoom;
            e.VisualItem.ImageAlignment = ContentAlignment.MiddleCenter;
        }

        void radListViewGallery_ItemDataBound(object sender, Telerik.WinControls.UI.ListViewItemEventArgs e)
        {
            var databoundItem = e.Item.DataBoundItem as MyImageObject;
            e.Item.Image = databoundItem.Image;
            e.Item.Text = databoundItem.FilePath;
        }

 

more details about the ListView

 class MyImageObject
        {
            public Image Image { get; set; }
            public string FilePath { get; set; }
            public MyImageObject(Image img, string filePath)
            {
                this.Image = img;
                this.FilePath = filePath;
            }
        }

 private void RefreshFileList(string _filePath, FileFilterType _filterType)
        {
            List<String> fileList = new List<String>();
            if (_filterType == FileFilterType.All)
            {
                var extensionFilter = new String[] { "*.png", "*.bmp", "*.jpg", "*.mp4" };
                foreach (String extension in extensionFilter)
                {
                    String[] files = Directory.GetFiles(_filePath, extension, SearchOption.TopDirectoryOnly);
                    foreach (String file in files)
                        fileList.Add(file);
                }
            }

            if (_filterType == FileFilterType.Video) fileList = Directory.GetFiles(_filePath, "*.mp4", SearchOption.TopDirectoryOnly).ToList();

            if (_filterType == FileFilterType.Images)
            {
                var extensionFilter = new String[] { "*.png", "*.bmp", "*.jpg" };
                foreach (String extension in extensionFilter)
                {
                    String[] files = Directory.GetFiles(_filePath, extension, SearchOption.TopDirectoryOnly);
                    foreach (String file in files)
                        fileList.Add(file);
                }
            }

            imageList.Clear();
            foreach (var mediaFileName in fileList.OrderByDescending(f => f))
            {
                var fileNameLowCase = mediaFileName.ToLower();
                if (fileNameLowCase.Contains(".png") || fileNameLowCase.Contains(".bmp") || fileNameLowCase.Contains(".jpg"))
                {
                    var tempImage = Image.FromFile(fileNameLowCase);
                    Bitmap pic = new Bitmap(96, 64);
                    using (Graphics g = Graphics.FromImage(pic))
                    {
                        g.DrawImage(tempImage, new Rectangle(0, 0, pic.Width, pic.Height));
                    }
                    imageList.Add(new MyImageObject(pic, fileNameLowCase));
                    tempImage.Dispose();
                }
                if (fileNameLowCase.Contains(".mp4"))
                {
                    var thumb = getThumbnail(fileNameLowCase);
                    if (thumb == null)
                    {
                        Bitmap pic = new Bitmap(96, 64);
                        using (Graphics g = Graphics.FromImage(pic))
                        {
                            g.DrawImage(ICUSBCamera.Properties.Resources.play_button, new Rectangle(0, 0, pic.Width, pic.Height));
                        }
                        imageList.Add(new MyImageObject(pic, fileNameLowCase));
                    } else imageList.Add(new MyImageObject(thumb, fileNameLowCase));


                }
            }
            radListViewGallery.DataSource = imageList;
        }


 

 

 

2 Answers, 1 is accepted

Sort by
0
Accepted
Dess | Tech Support Engineer, Principal
Telerik team
answered on 20 May 2022, 03:04 PM

Hello, David,   

Following the provided code snippets, I built a project to simulate as close as possible the described scenario. However, I commented some parts of the code in order to be able to build the project and run it locally. 
Please refer to the attached sample project which result is illustrated in the below screenshot:

It is important to note that for each internal element inside the visual item, it is necessary to set the ShouldHandleMouseInput property to false and the NotifyParentOnMouseInput property to true to enable the items selection when clicking on the custom elements. 

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, Principal
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/.

David
Top achievements
Rank 1
Iron
Iron
Iron
commented on 20 May 2022, 07:22 PM

Thanks, this is looking really good!

I had to set  ShouldHandleMouseInput  to true to get the buttons to handle mouse clicks, and the ListViewItems still do respond to selection.

I can work my way up the .Parent chain to get the data bound to the ListViewItem.

But now I have another question that is probably not specific to Kendo, but maybe someone can offer some help...

 

In the button click event defined inside my custom GalleryViewItem, how can I then raise an event on the parent form? Or at least call a method on that form?

One of my custom buttons is a delete button, and I need to tell the form to refresh the Listview after the deletion.

 

 

  

David
Top achievements
Rank 1
Iron
Iron
Iron
commented on 20 May 2022, 09:29 PM

I figured it out. I added a reference to the form in the data bound item
0
David
Top achievements
Rank 1
Iron
Iron
Iron
answered on 20 May 2022, 03:51 PM
Thanks, looks great!  I'll be trying out today and will let you know how it turns out.
David
Top achievements
Rank 1
Iron
Iron
Iron
commented on 15 Jun 2022, 10:14 PM

I have a follow-up on this topic.

I am on a new project now, and we need a more complex display. But luckily no interaction/buttons. I would like to use a row/column layout within the custom visual element. So, I have a title text, in row 0, with a colspan of 3. An image element in row 2 also with colspan of all 3 columns. Then I have 3 more rows of 3 values each. And I need all of that for each entry in the ListView.

I put together all of the code using RadPanel, RadLabel, and RadPictureBOx but then realized I cannopt add those kindsof controls to the Children of an IconListViewVisualItem...

I think I can convert the RadLabels and RadPictureBox to LightVisualItem, but the part that is stopping me is the table layout.

 

 

 

 

Dess | Tech Support Engineer, Principal
Telerik team
commented on 17 Jun 2022, 07:41 AM

Hello, David,

Note that you can simulate a tabular elements presentation with the help of multiple StackLayoutElements which can be vertical or horizontal. I have prepared a sample code snippet for your reference which result is illustrated below. Feel free to modify and extend it in a way which suits your requirements best:  
        public class CustomIconListViewVisualItem : IconListViewVisualItem
        {
            protected override Type ThemeEffectiveType
            {
                get
                {
                    return typeof(IconListViewVisualItem);
                }
            }

            StackLayoutElement mainContainer = new StackLayoutElement();
            StackLayoutElement row1 = new StackLayoutElement();
            StackLayoutElement row2 = new StackLayoutElement();
            StackLayoutElement row3 = new StackLayoutElement();
            StackLayoutElement row4 = new StackLayoutElement();
            StackLayoutElement row5 = new StackLayoutElement();
            LightVisualElement titleElement = new LightVisualElement();
            LightVisualElement imageElement = new LightVisualElement();
            LightVisualElement firstName = new LightVisualElement();
            LightVisualElement lastName = new LightVisualElement();
            LightVisualElement dateElement = new LightVisualElement();
            LightVisualElement footerElement = new LightVisualElement();
            protected override void CreateChildElements()
            {
                base.CreateChildElements();

                mainContainer.Orientation = Orientation.Vertical;
                mainContainer.StretchHorizontally = true;
                mainContainer.StretchVertically = true;
                this.Children.Add(mainContainer);
                mainContainer.Children.Add(row1);
                row1.Orientation = Orientation.Horizontal;
                row1.StretchHorizontally = true;
                mainContainer.Children.Add(row2);
                row2.Orientation = Orientation.Horizontal;
                row2.StretchHorizontally = true;
                mainContainer.Children.Add(row3);
                row3.Orientation = Orientation.Horizontal;
                row3.StretchHorizontally = true;
                mainContainer.Children.Add(row4);
                row4.Orientation = Orientation.Horizontal;
                row4.StretchHorizontally = true;
                mainContainer.Children.Add(row5);
                row5.Orientation = Orientation.Horizontal;
                row5.StretchHorizontally = true;

                row1.Children.Add(titleElement);
                titleElement.StretchHorizontally = true;
                row2.Children.Add(imageElement);
                imageElement.StretchHorizontally = true;
                row3.Children.Add(firstName);
                row3.Children.Add(lastName);
                row4.Children.Add(dateElement);
                dateElement.StretchHorizontally = true;
                dateElement.TextAlignment = ContentAlignment.MiddleCenter;
                row5.Children.Add(footerElement);
                footerElement.StretchHorizontally = true;
                footerElement.TextAlignment = ContentAlignment.MiddleCenter;
            }

            protected override void SynchronizeProperties()
            {
                base.SynchronizeProperties();
                this.DrawText = false;
                this.titleElement.Text = "Title" + this.Data.ListView.Items.IndexOf(this.Data);
                this.imageElement.Image= Image.FromFile(@"..\..\print-icon.png");
                this.firstName.Text= "First Name " + this.Data.ListView.Items.IndexOf(this.Data);
                this.lastName.Text= "Last Name" + this.Data.ListView.Items.IndexOf(this.Data);
                this.dateElement.Text = DateTime.Now.AddDays(this.Data.ListView.Items.IndexOf(this.Data)).ToShortDateString();
                this.footerElement.Text= "Footer" + this.Data.ListView.Items.IndexOf(this.Data);
            }
        }

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