I have a templated control in my UWP application which contains a ListView. The ListView is populated in the runtime.
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Renderer"
xmlns:triggers="using:Microsoft.Toolkit.Uwp.UI.Triggers">
<Style x:Key="RendererDefaultStyle" TargetType="local:Renderer" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:Renderer">
<Grid>
....
<ListView x:Name="AnnotsList" Margin="0,12,0,0" SelectionMode="None" Grid.Row="1" VerticalAlignment="Stretch" IsItemClickEnabled="True" Visibility="{Binding IsAnnotationsListOpen, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ItemContainerStyle="{StaticResource AnnotationsListViewItemStyle}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding}" />
<TextBlock Text="{Binding DisplayTitle}" Margin="20,0,0,10" FontSize="12" TextWrapping="WrapWholeWords" Visibility="Visible" />
</StackPanel>
<CommandBar Grid.Column="1">
<CommandBar.SecondaryCommands>
<AppBarElementContainer>
<StackPanel Orientation="Horizontal">
<Button x:Name="btn_RemoveFromList" DataContext="{Binding}">
<Button.Content>
<SymbolIcon Symbol="Delete" />
</Button.Content>
<ToolTipService.ToolTip>
<ToolTip Content="Delete" Placement="Mouse" />
</ToolTipService.ToolTip>
</Button>
</StackPanel>
</AppBarElementContainer>
</CommandBar.SecondaryCommands>
</CommandBar>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.GroupStyle>
<GroupStyle >
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Border AutomationProperties.Name="{Binding Key}">
<TextBlock Text="{Binding Key}" Style="{ThemeResource TitleTextBlockStyle}"/>
</Border>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
....
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:Renderer" BasedOn="{StaticResource RendererDefaultStyle}"/>
</ResourceDictionary>
I tried to bind a click event to the button like this but since it is dynamically generated it doesn't work.
public sealed class Renderer: Control, IDisposable
{
....
private void UpdateAnnotationsListView()
{
(GetTemplateChild("AnnotsList") as ListView).ItemsSource = null;
var source = AnnotationAdapter.GetGroupedAnnotations(); // ObservableCollection<ListViewGroupInfo>
var viewSource = new CollectionViewSource
{
IsSourceGrouped = true, Source = source
};
(GetTemplateChild("AnnotsList") as ListView).ItemsSource = viewSource.View;
if (viewSource.View.Count > 0)
{
(GetTemplateChild("btn_RemoveFromList") as Button).Click -= null;
(GetTemplateChild("btn_RemoveFromList") as Button).Click += async delegate(object sender, RoutedEventArgs e)
{
await OpenRemoveConfirmationAsync();
};
}
}
....
}
List source is a ObservableCollection
of type
public class ListViewGroupInfo: List < object >
{
public ListViewGroupInfo() {}
public ListViewGroupInfo(IEnumerable < object > items): base(items) {}
public object Key
{
get;
set;
}
}
List source is structured in such a way where I can group the list items accordingly.
This is a sample of the rendered ListView for more context.
The Delete buttons are the ones I'm trying to work with here.
I want to bind a method to the click event of those buttons in the ListView.
I Cannot use the name attribute since there can be multiple buttons as the list grows.
Since this button is in a templated control & generated in the runtime, I couldn't find a way to bind a method to the click event.
My guess is that I will have to bind a command to the button. But I couldn't find a way to do that either.
I did not use MVVM pattern in the templated control.
Could anyone help me with this? Any help is much appreciated.
After a whole bunch of research & trial and error, I ended up with a different approach as @nico-zhu-msft suggested.
Basically, I moved the ListView to a separate user control & observed property changes from the parent template control. In order to bind data to the
ListView
used a view-model.AssnotationsList.xaml
AnnotationsList.xaml.cs
AnnotationsListViewModel.cs
Replaced the ListView with the user control
Renderer.cs
like this.In the parent control class
Renderer.cs
(template control) got a reference to theAnnotationsList
control like this when parent is first rendered & bound thePropertyChanged
event.Added the following code to trigger on property changes in the
AnnotationsList
control.For now it is configured to trigger on
ItemClick
event of theListViewItems
.Hope this helps someone who might be looking for a similar solution.