0

After extensive researching I have not found an answer to this problem. I have a list box whose ItemsSource is a collection of Button objects. When I add a button to the collection it appears properly but when clicked the command is not executed. I have already implemented RelayCommand and it is used throughout my code.

C# MVVM WPF

The View

 <ListBox ItemsSource="{Binding Buttons}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <ListBox.ItemTemplate> <DataTemplate> <Button Margin="5,5,5,5" Content="{Binding Content}" Command="{Binding ExecuteButtonCommand}" CommandParameter="{Binding CommandParameter}" /> </DataTemplate> </ListBox.ItemTemplate> </ListBox> 

The ViewModel

 public RelayCommand _executeButtonCommand; public ICommand ExecuteButtonCommand { get { if (_executeButtonCommand == null) _executeButtonCommand = new RelayCommand(exec => this.ButtonCommands(param)); return _executeButtonCommand; } } 

For Testing I have this code.

 public void AddButtons() { Buttons= new ObservableCollection<Button>(); Button btn = new Button(); btn.Content = "Generate Files"; btn.Command = "{Binding ExecuteButtonCommand}"; btn.CommandParameter = "Files"; Buttons.Add(btn); } 

But I cannot assign the Command that way. The rest of the button works correctly. So I put the Command= in the view as you see above.

If this has been answered, then I can't find it. The nearest answer is nine years old and does not work.

Thanks for looking.

2 Answers 2

1

What is happening is that the ListBox's DataTemplate is trying to bind to a property called ExecuteButtonCommand which doesn't exist in Button object. And then, to bind the parameter, you need to point to your view's DataContext.

Change it to:

<ListBox.ItemTemplate> <DataTemplate> <Button Margin="5,5,5,5" Content="{Binding Content}" Command="{Binding Command}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window},Path=DataContext.MyParameter}" /> </DataTemplate> </ListBox.ItemTemplate> 

For clarification, I created a property called "MyParameter" in my ViewModel. Also, in your codebehind, change your button creation code to:

Buttons = new ObservableCollection<Button>(); Button btn = new Button(); btn.Content = "Generate Files"; btn.Command = ExecuteButtonCommand; Buttons.Add(btn); 

And your ExecuteButtonCommand to simply:

 public ICommand ExecuteButtonCommand { get { if (_executeButtonCommand == null) _executeButtonCommand = new RelayCommand(ButtonCommands); return _executeButtonCommand; } } 
Sign up to request clarification or add additional context in comments.

2 Comments

Excellent, Mari! The Parameter part of my question was messed up because of all of the different methods I tried. I put the btn.CommandParameter = back into the button creation. It worked perfectly. Now I can move forward to adding the rest of the buttons. I guess I got close to the solution. But everything was just a little off. Now I see what it was. Again, thank you.
Good! Glad it helped! :)
1

I wanted to close this out with the final result in case someone else is searching for the same answer. Mari set me straight which led to this example below as the final result. There is no "Code Behind." Generation of the buttons is done in the view model. After a button is created it is added to the button collection which is the source for the ListBox. I am only including the code specific to the question.

This is how it ended up.

The View

 <ListBox ItemsSource="{Binding Buttons, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="AliceBlue" BorderBrush="Transparent" ScrollViewer.HorizontalScrollBarVisibility="Disabled" SelectedItem=""> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel IsItemsHost="True" /> </ItemsPanelTemplate> </ListBox.ItemsPanel> <ListBox.ItemTemplate> <DataTemplate> <Button Margin="5,5,5,5" Content="{Binding Content}" Command="{Binding Command}" CommandParameter="{Binding CommandParameter}" /> </DataTemplate> </ListBox.ItemTemplate> </ListBox> 

The ViewModel - A switch statement is used to determine what button needs to be generated. I gave the button a name because I wanted to be able to find it in the collection and set the Enabled property. But that didn't work and I still haven't found an answer.

 public void AddButton(string param) { Button btn = new Button(); switch (param) { case "Files": btn.Content = "Do Files"; btn.CommandParameter = "Files"; btn.Name = "Files"; break; //More items here } btn.Command = ExecuteButtonCommand; //The ICommand name. I made this harder than it needed to be! Buttons.Add(btn); } public RelayCommand _executeButtonCommand; public ICommand ExecuteButtonCommand { get { if (_executeButtonCommand == null) _executeButtonCommand = new RelayCommand(param => this.ButtonCommands(param)); return _executeButtonCommand; } } 

I hope that can help someone.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.