I am trying to add a button to a custom ListView (MyListView) which triggers a command (MyCustomCommand) defined in MyListView. I have added the button (and a title text) by applying a ControlTemplate. The problem is that I have not found a way to trigger MyCustomCommand when clicking the button. What I eventually want to achieve is to open a Popup or ContextMenu where I can select which columns should be visible in the ListView.
Here's my template source:
<Style TargetType="local:MyListView">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyListView">
<Border Name="Border" BorderThickness="1" BorderBrush="Black">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Background="LightSteelBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Margin="3,3,3,3" Text="{TemplateBinding HeaderTitle}" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Stretch" FontSize="16" />
<Button Margin="3,3,3,3" Grid.Column="1"
VerticalAlignment="Center" HorizontalAlignment="Right" Height="20"
Command="{TemplateBinding MyCustomCommand}">A button</Button>
</Grid>
<ScrollViewer Grid.Row="1" Style="{DynamicResource {x:Static GridView.GridViewScrollViewerStyleKey}}">
<ItemsPresenter />
</ScrollViewer>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here is the definition for MyListView:
public class MyListView : ListView
{
public static readonly DependencyProperty MyCustomCommandProperty =
DependencyProperty.Register("MyCustomCommand", typeof(ICommand), typeof(MyListView));
private static RoutedCommand myCustomCommand;
public ICommand MyCustomCommand
{
get
{
if (myCustomCommand == null)
{
myCustomCommand = new RoutedCommand("MyCustomCommand", typeof(MyListView));
var binding = new CommandBinding();
binding.Command = myCustomCommand;
binding.Executed += binding_Executed;
CommandManager.RegisterClassCommandBinding(typeof(MyListView), binding);
}
return myCustomCommand;
}
}
private static void binding_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Command Handled!");
}
public static readonly DependencyProperty HeaderTitleProperty =
DependencyProperty.Register("HeaderTitle", typeof(string), typeof(MyListView));
public string HeaderTitle { get; set; }
}
And here is the XAML that creates a simple instance of MyListView:
<local:MyListView VerticalAlignment="Top" HeaderTitle="ListView title">
<ListView.View>
<GridView>
<GridViewColumn Width="70" Header="Column 1" />
<GridViewColumn Width="70" Header="Column 2" />
<GridViewColumn Width="70" Header="Column 3" />
</GridView>
</ListView.View>
<ListViewItem>1</ListViewItem>
<ListViewItem>2</ListViewItem>
<ListViewItem>1</ListViewItem>
<ListViewItem>2</ListViewItem>
</local:MyListView>
Notice HeaderTitle which is bound to the DependencyProperty in MyListView. This works as expected. Why doesn't it work the same way with commands? Any clues of how to make this work?
You should start by making the wrapper property for the command static and use
Command={x:Static local:MyListView.MyCustomCommand}
Generally you only want an ICommand property if the command is being set to a different value on each instance (like Button) or if it's something like a DelegateCommand/RelayCommand on a ViewModel. You should also remove all of the extra code in the getter and instead initialize the command either inline or in the static constructor and connect the CommandBinding in the control's instance constructor.
CommandBindings.Add(new CommandBinding(MyCustomCommand, binding_Executed));
**UPDATE
The RoutedCommand itself should be declared as static. ICommand instance properties are good for when an external consumer of your control is passing in a command to execute, which is not what you want here. There is also no need for a DP here and the one you're using is declared incorrectly - to be usable they need to have instance wrapper properties with GetValue/SetValue.
public static RoutedCommand ShowColumnPickerCommand
{
get; private set;
}
static MyListView()
{
ShowColumnPickerCommand = new RoutedCommand("ShowColumnPickerCommand", typeof(MyListView));
}