2010-10-06 37 views
6

Tôi đang cố thêm một nút vào một ListView tùy chỉnh (MyListView) kích hoạt một lệnh (MyCustomCommand) được định nghĩa trong MyListView. Tôi đã thêm nút (và một văn bản tiêu đề) bằng cách áp dụng một ControlTemplate. Vấn đề là tôi đã không tìm thấy một cách để kích hoạt MyCustomCommand khi nhấp vào nút. Những gì tôi cuối cùng muốn đạt được là mở một Popup hoặc ContextMenu nơi tôi có thể chọn cột nào sẽ hiển thị trong ListView.WPF: Liên kết với lệnh từ ControlTemplate

Đây là nguồn mẫu của tôi:

<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> 

Dưới đây là định nghĩa cho 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; } 
} 

Và đây là XAML mà tạo ra một ví dụ đơn giản của 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> 

Chú ý HeaderTitle được gắn với DependencyProperty trong MyListView. Điều này hoạt động như mong đợi. Tại sao nó không hoạt động theo cùng một cách với các lệnh? Bất kỳ manh mối nào về cách thực hiện công việc này?

Trả lời

2

Tôi không chắc đây có phải là cách chính xác để thực hiện việc này hay không. Đó là một chút khó khăn để đọc mã nguồn trong ý kiến, vì vậy tôi viết thư trả lời này như một câu trả lời ...

Dưới đây là các nhà xây dựng của MyListView + các phương pháp ràng buộc lệnh:

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; 
} 

Các bindings không được thiết lập trong một bối cảnh tĩnh. Những điều duy nhất mà là tĩnh là những thuộc tính phụ thuộc cho các lệnh và các lệnh riêng của mình:

public static readonly DependencyProperty ShowColumnPickerCommandProperty = 
    DependencyProperty.Register("ShowColumnPickerCommand", typeof(RoutedCommand), typeof(MyListView)); 

private static RoutedCommand showColumnPickerCommand; 

public static RoutedCommand ShowColumnPickerCommand 
{ 
    get 
    { 
     return showColumnPickerCommand; 
    } 
} 

Lệnh cần phải được tĩnh để có thể liên kết với nó từ XAML như thế này:

<Button Command="{x:Static local:MyListView.ShowColumnPickerCommand}" /> 
6

Bạn nên bắt đầu bằng cách làm cho tài sản wrapper cho lệnh tĩnh và sử dụng

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

Nói chung, bạn chỉ muốn có một tài sản ICommand nếu lệnh đã được thiết lập để một giá trị khác nhau trên từng trường hợp (như Button) hoặc nếu nó giống như một DelegateCommand/RelayCommand trên một ViewModel. Bạn cũng nên loại bỏ tất cả các mã phụ trong getter và thay vào đó khởi tạo lệnh hoặc inline hoặc trong constructor tĩnh và kết nối CommandBinding trong constructor instance của control.

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

* * CẬP NHẬT

Các RoutedCommand bản thân nên được khai báo là tĩnh. Các thuộc tính của ICommand là tốt cho khi một người tiêu dùng bên ngoài kiểm soát của bạn đi qua trong một lệnh để thực hiện, đó không phải là những gì bạn muốn ở đây. Cũng không cần một DP ở đây và cái bạn đang sử dụng được khai báo không chính xác - để có thể sử dụng được, chúng cần phải có các thuộc tính wrapper dụ với GetValue/SetValue.

public static RoutedCommand ShowColumnPickerCommand 
{ 
    get; private set; 
} 

static MyListView() 
{   
    ShowColumnPickerCommand = new RoutedCommand("ShowColumnPickerCommand", typeof(MyListView)); 
} 
+0

Cảm ơn rất nhiều. Điều đó giải quyết trường hợp của tôi :) Bây giờ tôi có thể mở một Popup khi lệnh thực thi. –

+0

Tôi đã gặp sự cố mới ... Nút kích hoạt lệnh chỉ khả dụng (được bật) trong phiên bản đầu tiên của MyListView trong cửa sổ. Nó có liên quan gì đến từ khóa Static trong: Command = {x: Static local: MyListView.MyCustomCommand} –

+0

Các nút có lệnh bị vô hiệu hóa khi lệnh CanExecute của lệnh là sai hoặc lệnh không có Trình xử lý thực thi được đính kèm. Hãy chắc chắn rằng bạn không có bất cứ điều gì lạ xảy ra với CanExecute và CommandBinding đang được thiết lập trên mỗi thể hiện ListView và không phải trong một bối cảnh tĩnh mà sẽ chỉ ảnh hưởng đến một trong những đầu tiên. –

Các vấn đề liên quan