I have a scenario where I have "dynamic" content in a listview. I am making a sort of chat application where you can send hyperlinks, images, videos, etc.
I have a template defined in XAML for an incoming message and outgoing message, but I need to be able to say "this message has an image", "this message has a link", "this message has a text body with a link in the middle of it", "this message has both text and 2 images", etc.
How can I dynamically set what content is in each listview item without having to define a bunch of things that are IsVisible="true/false"?
3 Answers, 1 is accepted
Dynamically updating an existing item's content after it's been added is not really the best way to go. Instead you would have already decided what type of item will be added and choose the appropriate template for that message using the TemplateSelector
In the documentaiotn, you'll see different types of classes for message. For example, we ship TextMessage out of the box because it's a guranteed message type across the available platforms.,
The control was explicitly designed as platform and model agnostic so that you have the flexibility to define the Message class that will be used for the service. It's the ItemTemplateSelector determines what template to use in the list dependeing on what kind of message it is.
I recommend reviewing our four main examples to gain a better understanding of how this works. A good place to start is the TravelAssistant example because it has a Template selector that returns a SummaryTemplate, FlightTemplate or WaitingForBotTemplate depending on the ChatItem's content.
In your case you could define a ImageMessageTemplate, VideoMessageTemplate, LinkMessageTemplate and so forth. As the items is pulled in from the data source, you explicitly put it in the backing collection as that message type.
Additional Guidance with Demo
You can extend TextMessage class and add your own properties to distinguish a particular message type from another. This way you can have custom templates for everythign and return the appropriate one.
Here's a simple example in which I extend TextMessage with special properties to let me know it's a ImageMessage, a WebUrlMessage.
When the data comes in from the service, you instantiate the appropriate message type for that item. In the example below I'm just randomly choosing the message type, but you should be able to determine what type of message it is at that type because of the incoming content.
Now you can define the template selector, using the Type of the message to determine which template to return:
Finally, here's what all of this comes together as in the UI:
and here's what that looks like at runtime:
Lance | Technical Support Engineer, Principal
The most logical thing in my opinion would be to simply bind a property to an icon's visibility (icon instead of a background color for added complexity on the layout side) instead of adding another template with only 1 added element.
I've experienced that the radlistview does not always show the changes in visibility of elements when using a single template.
If I were to use multiple itemplates, will the radlistview then automatically reload and show the newly correct template?
Can't find any documentation explaining if that's the case.
You're correct, TemplateSelectors by design do not listen for property changes and the templates do not get switched after it's been rendered. If you wanted to trigger the TemplateSelector to render an item with a different template, you would remove and re-add the item.
The resulting CollectionChanged event will trigger the TemplateSelector because a DataTemplate is needed for the item changes
Single DataTemplate Option
You've described the other good option with using a single item template. you can have a single DataTemplate that has UI elements for the different types of messages and show/hide/change parts of that template using properties of the message data model.
Using the same example from my earlier post, you can combine both ImageUrl and WebUrl in the same model and use a converter to show or hide the
and the converter looks something like this:
You could use a single DataTemplate like this:
The same concept applies for anything else, like BackgroundColor, showing/hiding icons, etc. The only thing you really need to be sure of is that you're invoking property changed in some way when that message gets updated.
For example, if you're just trying to update the values of a message that already exists, you can use the same approach I use above to locate the item:
If you did try this and you're not seeing any changes, it would be because the property on the model is not invoking PropertyChanged notification. Otherwise the binding in the template isn't informed of the value change and any converters (i.e. bool to color converter) wouldn't be triggered.
If you're using our Telerik.XamarinForms.ConversationalUI.TextMessage model as the base class, we already have INotifyPropertyChanged implemented. You can just call "OnPropertyChanged() in your property setters like I do above for ImageUrl and WebUrl.
If you have trouble, please share your code and steps to reproduce with us in a Support Ticket. You have a priority support license and can use this link to open a new ticket - Get Support (choose UI for Xamarin).
Tip - If you do open a ticket and your repro project isn't able to connect to the messaging service, please add some sample messages in the chat service logic (instead of trying to connect). This way we'll be able to directly see the data and provide a much faster time to solution.
Lance | Technical Support Engineer, Principal