Norgul Norgul - 12 days ago 5
C# Question

WPF Prism listbox button

I am pulling items from DB into a listbox which consists of several columns. I would like to add a delete button to each item I pull from DB, but I can't seem to forward the ID of the item, it always says 0.

<ListBox ItemsSource="{Binding LbPlugins}" HorizontalContentAlignment="Stretch" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

<CheckBox Grid.Column="0" Content="{Binding Name}" IsChecked="{Binding IsActive}"/>
<Label Grid.Column="1" Content="{Binding ClassName}"/>
<Button Grid.Column="2" Content="E" Command="{Binding btnEditPluginCommand}"/>
<Button Grid.Column="3" Content="D" Command="{Binding Path=DataContext.btnDeletePluginCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}" CommandParameter="{Binding PluginId}"/>

</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>


In ViewModel:

private int pluginId;
public int PluginId
{
get { return pluginId; }
set { SetProperty(ref pluginId, value); }
}
public DelegateCommand btnDeletePluginCommand { get; set; }


...

in constructor

btnDeletePluginCommand = new DelegateCommand(DeletePlugin);


...

private void DeletePlugin()
{
var result = MessageBox.Show("Are you sure you want to delete this plugin?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (result == DialogResult.Yes)
{
MessageBox.Show("YAY, ID=" + pluginId);
}
}

Answer

As you're using Prism you should use DelegateCommand, that is Prism's ICommand implementation.

In order to make this work you need to use an object or a nullable type as argument for the generic CommandDelegate. If you fail to do this, you'll get an InvalidCastException at runtime.

Declare your command like this:

public ICommand btnDeletePluginCommand { get; set; }

Initialize it on viewmodel's constructor:

btnDeletePluginCommand = new DelegateCommand<int?>(DeletePlugin);

And refactor your method:

private void DeletePlugin(int? pluginId)
{
    if (pluginId == null) return;

    var result = MessageBox.Show("Are you sure you want to delete this plugin?", "", MessageBoxButtons.YesNo,
        MessageBoxIcon.Warning);
    if (result == DialogResult.Yes)
        MessageBox.Show("YAY, ID=" + pluginId);
}

As you did bind the command to the ListBox, pluginId parameter will never be null, but you should always validate. Maybe you use this viewmodel with other UI components?

By the way, you shouldn't be using MessageBox in the viewmodel. I guess it's a proof of concept or something :). In the case of MVVM you should inject a DialogService or use InteractionRequests to show notifications from your viewmodel.

Hope this helps!