我正在尝试向自定义ListView(MyListView)添加一个按钮,该按钮触发MyListView中定义的命令(MyCustomCommand)。我通过应用ControlTemplate添加了按钮(和标题文本)。问题是我没有找到一种方法来点击按钮时触发MyCustomCommand。我最终想要实现的是打开一个Popup或ContextMenu,我可以在其中选择哪些列应该在ListView中可见。
这是我的模板来源:
<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>
以下是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; }
}
这是创建MyListView的简单实例的XAML:
<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>
注意HeaderTitle绑定到MyListView中的DependencyProperty。这按预期工作。为什么命令不能以相同的方式工作?有关如何使这项工作的任何线索?
答案 0 :(得分:6)
首先应该为命令static设置包装属性并使用
Command={x:Static local:MyListView.MyCustomCommand}
通常,如果在每个实例(如Button)上将命令设置为不同的值,或者在ViewModel上类似于DelegateCommand / RelayCommand,则只需要ICommand属性。您还应该删除getter中的所有额外代码,而是在内联或静态构造函数中初始化命令,并在控件的实例构造函数中连接CommandBinding。
CommandBindings.Add(new CommandBinding(MyCustomCommand, binding_Executed));
*的 * UPDATE 强>
RoutedCommand本身应该声明为static。当控件的外部使用者传入要执行的命令时,ICommand实例属性很有用,这不是您想要的。此处也不需要DP,并且您正在使用的DP声明不正确 - 为了可用,它们需要具有GetValue / SetValue的实例包装器属性。
public static RoutedCommand ShowColumnPickerCommand
{
get; private set;
}
static MyListView()
{
ShowColumnPickerCommand = new RoutedCommand("ShowColumnPickerCommand", typeof(MyListView));
}
答案 1 :(得分:3)
我不确定这是否是正确的方法。在评论中阅读源代码有点困难,所以我把这个回复写成答案......
这是MyListView的构造函数+命令绑定方法:
public MyListView()
{
showColumnPickerCommand = new RoutedCommand("ShowColumnPickerCommand", typeof(MyListView));
var binding = new CommandBinding();
binding.Command = showColumnPickerCommand;
binding.Executed += ShowColumnPicker;
binding.CanExecute += ShowColumnPickerCanExecute;
CommandBindings.Add(binding);
}
private void ShowColumnPicker(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Show column picker");
}
private void ShowColumnPickerCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
绑定不是在静态上下文中设置的。唯一静态的是命令的DependencyProperty和命令本身:
public static readonly DependencyProperty ShowColumnPickerCommandProperty =
DependencyProperty.Register("ShowColumnPickerCommand", typeof(RoutedCommand), typeof(MyListView));
private static RoutedCommand showColumnPickerCommand;
public static RoutedCommand ShowColumnPickerCommand
{
get
{
return showColumnPickerCommand;
}
}
该命令需要是静态的才能从XAML绑定到它,如下所示:
<Button Command="{x:Static local:MyListView.ShowColumnPickerCommand}" />