How to bind "command" and "CommandParameter" of a button in template(WinUI3)?

aluzi liu 486 Reputation points
2023-04-23T08:17:51.8066667+00:00

I have a WinUI3 project, I create a custom ListBoxItem style, because the ListBoxItem will use in multiple pages, so I put it in App.xaml ResourceDictionary. When I try to bind the command of button, I try:

<Button Command="{x:Bind DeleteCommand}">Delete</Button>

But xaml complier said "can not find DeleteCommand in ListBoxItem"(DeleteCommand is defined in MainWindow.xaml.cs) In wpf or Xamarin.Forms, I can use RelativeSource and AncestorType to locate the command, but in WinUI project, it seem that both "Binding" or "x:Bind" dose not have these property. Here is ListBoxItem style:

            <Style x:Key="TestListBoxItem" TargetType="ListBoxItem">
                <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                <Setter Property="VerticalContentAlignment" Value="Stretch"/>
                <Setter Property="FocusVisualPrimaryThickness" Value="0"/>
                <Setter Property="FocusVisualSecondaryThickness" Value="0"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListBoxItem">
                            <Border x:Name="Bd" Padding="10 4 0 4" Margin="10,0,10,0" CornerRadius="4" BorderThickness="1" BorderBrush="Transparent" Background="Transparent">
                                <VisualStateManager.VisualStateGroups>
                                    <VisualStateGroup x:Name="CommonStates">
                                        <VisualState x:Name="Normal" />

                                        <VisualState x:Name="PointerOver">
                                            <VisualState.Setters>
                                                <Setter Target="Bd.Background" Value="LightGray"/>
                                            </VisualState.Setters>
                                        </VisualState>

                                        <VisualState x:Name="Selected">
                                            <VisualState.Setters>
                                                <Setter Target="Bd.Background" Value="#335cad"/>
                                                <Setter Target="Bd.BorderBrush" Value="#335cad"/>
                                                <Setter Target="Label.Foreground" Value="White"/>
                                            </VisualState.Setters>
                                        </VisualState>

                                        <VisualState x:Name="SelectedUnfocused">
                                            <VisualState.Setters>
                                                <Setter Target="Bd.Background" Value="#335cad"/>
                                                <Setter Target="Bd.BorderBrush" Value="#335cad"/>
                                                <Setter Target="Label.Foreground" Value="White"/>
                                            </VisualState.Setters>
                                        </VisualState>

                                        <VisualState x:Name="SelectedPointerOver">
                                            <VisualState.Setters>
                                                <Setter Target="Bd.Background" Value="#335cad"/>
                                                <Setter Target="Bd.BorderBrush" Value="Yellow"/>
                                                <Setter Target="Label.Foreground" Value="White"/>
                                            </VisualState.Setters>
                                        </VisualState>
                                    </VisualStateGroup>

                                </VisualStateManager.VisualStateGroups>

                                <StackPanel Orientation="Horizontal" Spacing="10">
                                    <TextBlock x:Name="Label" VerticalAlignment="Center" Text="{Binding ItemName}"></TextBlock>
                                    <Button Command="{x:Bind DeleteCommand}">Delete</Button>
                                </StackPanel>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

And the Window xaml code:

<Grid>
    <ListBox Padding="0" ItemContainerStyle="{StaticResource TestListBoxItem}" ItemsSource="{x:Bind testListBoxItems}"/>
</Grid>

This is cs code:

    public class TestListBoxItem : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;

        public string ItemName { get; set; }
        public string Id { get; set; }

        public TestListBoxItem()
        {
            Id = "";
            ItemName = "";
        }

        private void FirePropertyChanged(string propertyName)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
    /// <summary>
    /// An empty window that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class ListBoxTest : Window
    {
        public List<TestListBoxItem> testListBoxItems { get; set; }
        public ListBoxTest()
        {
            this.InitializeComponent();
            testListBoxItems = new List<TestListBoxItem> {
                new TestListBoxItem { ItemName = "AAAAAAAAA", Id = "AAAA01" },
                new TestListBoxItem { ItemName = "BBBBBBBBB", Id = "ddd" }
            };
        }
    }
Windows development Windows App SDK
{count} votes

Accepted answer
  1. Anonymous
    2023-04-24T03:12:50.9633333+00:00

    Hello,

    Welcome to Microsoft Q&A!

    How to bind "command" and "CommandParameter" of a button in template(WinUI3)?

    What you need now is to create a command in the TestListBoxItem. And change the binding of the Button from x:Bind to Binding. You could refer to the following code: Xaml

    // the xaml code will pass the textblock as parameter. Just an example.
    <Button Command="{Binding DeleteCommand}" CommandParameter="{Binding ElementName=Label}">Delete</Button>
    

    C# Code

        public class TestListBoxItem : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler? PropertyChanged;
    
            public string ItemName { get; set; }
            public string Id { get; set; }
    
            public TestListBoxItem()
            {
                Id = "";
                ItemName = "";
            }
    
            private void FirePropertyChanged(string propertyName)
            {
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
            // create a delete command which used for binding
            public ICommand DeleteCommand
            {
                get
                {
                    return new CommadEventHandler<object>((obj) => this.DeleteSomething(obj));
                }
    
            }
            // delete method
            private void DeleteSomething(object obj)
            {
                try
                {
                    Debug.WriteLine("DeleteSomething");
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                }
            }
    
    
        }
        // custom command with parameter
        public class CommadEventHandler<T> : ICommand
        {
            public event EventHandler CanExecuteChanged;
    
            public Action<T> action;
            public bool CanExecute(object parameter)
            {
                return true;
            }
    
            public void Execute(object parameter)
            {
                this.action((T)parameter);
            }
            public CommadEventHandler(Action<T> action)
            {
                this.action = action;
    
            }
        }
    
    

    Thank you.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


1 additional answer

Sort by: Most helpful
  1. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.