WPF: привязка к команде из ControlTemplate - PullRequest
7 голосов
/ 06 октября 2010

Я пытаюсь добавить кнопку в пользовательский ListView (MyListView), который вызывает команду (MyCustomCommand), определенную в MyListView. Я добавил кнопку (и текст заголовка), применив 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; }
}

А вот XAML, который создает простой экземпляр 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>

Обратите внимание на заголовок заголовка, который привязан к свойству DependencyProperty в MyListView. Это работает как ожидалось. Почему это не работает так же с командами? Какие-нибудь подсказки, как заставить это работать?

Ответы [ 2 ]

6 голосов
/ 06 октября 2010

Вы должны начать с создания свойства оболочки для команды static и использовать

Command={x:Static local:MyListView.MyCustomCommand}

Как правило, свойство ICommand требуется только в том случае, если команде присваивается другое значение для каждого экземпляра (например, Button), или если это что-то вроде DelegateCommand / RelayCommand в ViewModel. Вам также следует удалить весь дополнительный код в получателе и вместо этого инициализировать команду либо встроенным, либо в статическом конструкторе и подключить CommandBinding в конструкторе экземпляра элемента управления.

CommandBindings.Add(new CommandBinding(MyCustomCommand, binding_Executed));

** UPDATE

Сама RoutedCommand должна быть объявлена ​​как статическая. Свойства экземпляра ICommand хороши для случаев, когда внешний потребитель вашего элемента управления передает команду для выполнения, что здесь не то, что вам нужно. Здесь также нет необходимости в DP, и тот, который вы используете, объявлен неправильно - для того, чтобы его можно было использовать, он должен иметь свойства оболочки экземпляра с GetValue / SetValue.

public static RoutedCommand ShowColumnPickerCommand
{
    get; private set;
}

static MyListView()
{        
    ShowColumnPickerCommand = new RoutedCommand("ShowColumnPickerCommand", typeof(MyListView));
}
3 голосов
/ 07 октября 2010

Я не уверен, что это правильный способ сделать это. Немного сложно прочитать исходный код в комментариях, поэтому я пишу этот ответ как ответ ...

Вот конструктор 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}" />
...