David Simões
David Simões

Reputation: 263

Data Template Button created in XamlReader don't firing events

I'm trying to create a ListView Page that works for every object in my app where I can show all the objects received by parameter from a List<object> where I don't know which object the page will have to handle, I also receive the fields to show as parameters in a List <string, string> where the first string is the type of the field (header/subheader/image) and for that, I had to use XAML Reader so I could create the data bindings in the code behind.

Here's my code:

protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            var param = (Dictionary<string, object>)e.Parameter;
            _ItemsList = (List<object>)param["itemsList"];
            _Fields = (Dictionary<string, string>)param["fields"];

            _DetailsPage = (Type)param["detailPage"];

            EditCommand = new UniversalListViewCommand();

            ObjListView.ItemsSource = UniversalAutoSuggestBox.ItemsSource = _ItemsList;
            MainStackPanel.DataContext = this;

            ObjListView.ItemTemplate = NormalItemTemplate = (DataTemplate)XamlReader.Load(GenerateDataTemplate("NormalItemTemplate"));
            SelectedItemTemplate = (DataTemplate)XamlReader.Load(GenerateDataTemplate("SelectedItemTemplate"));

        }

        public string GenerateDataTemplate(string param)
        {
            StringBuilder sbTemp = new();

            //Data Template definition
            if (param == "NormalItemTemplate") sbTemp.Append("<DataTemplate x:Key=\"NormalItemTemplate\" ");
            if (param == "SelectedItemTemplate") sbTemp.Append("<DataTemplate x:Key=\"SelectedItemTemplate\" ");

            //sbTemp.Append("x:Class = \"xizPrototipo_0_2.Pages.UniversalListViewPage\" ");
            sbTemp.Append(@"xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" ");
            sbTemp.Append(@"xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">");

            //Grid definition
            sbTemp.Append("<Grid MinWidth=\"350\" Margin=\"5\">");

            //Grid row definition
            sbTemp.Append("<Grid.RowDefinitions>");
            sbTemp.Append("<RowDefinition Height = \"*\" />");
            sbTemp.Append("<RowDefinition Height = \"*\" />");
            sbTemp.Append("<RowDefinition Height = \"*\" />");
            sbTemp.Append("</Grid.RowDefinitions>");

            //Grid column definition
            sbTemp.Append("<Grid.ColumnDefinitions>");
            sbTemp.Append("<ColumnDefinition Width = \"Auto\"/>");
            sbTemp.Append("<ColumnDefinition Width = \"*\" />");
            sbTemp.Append("</Grid.ColumnDefinitions>");

            //Ellipse definition 
            sbTemp.Append("<Ellipse Grid.Row=\"0\" Grid.RowSpan=\"2\" Width = \"32\" Height = \"32\" Margin = \"6\" VerticalAlignment = \"Center\" HorizontalAlignment = \"Center\">");
            sbTemp.Append("<Ellipse.Fill> <ImageBrush x:Name =\"LogoImage\" ImageSource = \"{Binding " + _Fields["Image"] + "}\" /> </Ellipse.Fill> ");
            sbTemp.Append("</Ellipse>");

            //Header Text Block Definition
            sbTemp.Append("<TextBlock Grid.Row = \"0\" Grid.Column = \"1\" Text = \"{Binding " + _Fields["Header"] + "}\" Style = \"{ThemeResource BaseTextBlockStyle}\" Margin = \"12,6,0,0\"/> ");

            //Subheader Text Block Definition 
            sbTemp.Append("<TextBlock  Grid.Row=\"1\" Grid.Column = \"1\" Text = \"{Binding " + _Fields["Subheader"] + "}\" Style = \"{ThemeResource BodyTextBlockStyle}\" Margin = \"12,0,0,6\" /> ");

            //Button (case Selected)
            if (param == "SelectedItemTemplate")
            {
                sbTemp.Append("<StackPanel Grid.Row=\"2\" Grid.Column=\"1\" Orientation =\"Horizontal\" HorizontalAlignment =\"Right\" Spacing = \"5\" > ");
                sbTemp.Append("<Button x:Name=\"EditButton\" Content=\"Editar\" Click=\"AlterButton_Click\" />");
                sbTemp.Append("</StackPanel>");
            }

            //Grid end
            sbTemp.Append("</Grid>");
            //DataTemplate end
            sbTemp.Append("</DataTemplate>");

            return sbTemp.ToString();
        }

With this method I could get the outcome that I wanted but when I click the button created in the following line it don't fires any event:

  sbTemp.Append("<Button x:Name=\"EditButton\" Content=\"Editar\" Click=\"AlterButton_Click\" />");

I also tried using commands, Data Template selector and still I couldn't do anything with that button.

Does anyone know how can I put that button to work?

(Yes, I have the event on the button created and a function to change the Data Template to show the button.)

Upvotes: 0

Views: 91

Answers (1)

Nico Zhu
Nico Zhu

Reputation: 32775

Data Template Button created in XamlReader don't firing events

I am afraid it will not respond to the click event handler created from the string xaml. Because the click event registration process will be saved in the xxpage.g.cs file during pre-compilation. However, if you load the data template from the string runtime. It will not register for this event.

So the better way is binding command for button.

For example

 public MainPage()
{
    this.InitializeComponent();

    DataTemplate itmeTemplate = (DataTemplate)XamlReader.Load(
       @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
       <Button Command='{Binding BtnClickCommand}' Content='Editor' />
       </DataTemplate>");
    TestListView.ItemTemplate = itmeTemplate;

    NumbersList = new ObservableCollection<Item>();
    for (int i = 0; i < 50; i++)
    {
        var item = new Item ();
        NumbersList.Add(item);
    }
    TestListView.ItemsSource = NumbersList;
}

public ObservableCollection<Item> NumbersList { get; set; }

Model

public class Item : INotifyPropertyChanged
{
   
    public ICommand BtnClickCommand
    {
        get
        {
            return new RelayCommand(() =>
            {


            });
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        // Raise the PropertyChanged event, passing the name of the property whose value has changed.
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

}

Xaml Code

<Grid x:Name="RootGrid">
    <ListView
        x:Name="TestListView"
        ItemsSource="{x:Bind NumbersList}"
        Visibility="Visible">
    </ListView>
</Grid>

Update 1

public MainPage()
{
    this.InitializeComponent();

    this.DataContext = this;
 
    DataTemplate itmeTemplate = (DataTemplate)XamlReader.Load(
       @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
       <Button Command='{Binding DataContext.BtnClickCommand, ElementName=TestListView}' Content='Editor' />
       </DataTemplate>");
    TestListView.ItemTemplate = itmeTemplate;

    NumbersList = new ObservableCollection<Item>();
    for (int i = 0; i < 50; i++)
    {
        var item = new Item ();
        NumbersList.Add(item);
    }
    TestListView.ItemsSource = NumbersList;
}

public ICommand BtnClickCommand
{
    get
    {
        return new RelayCommand(async () =>
        {
        });
    }
}

Upvotes: 1

Related Questions