2010-10-06 135 views
6

我想添加一個按鈕到自定義ListView(MyListView),它觸發MyListView中定義的命令(MyCustomCommand)。我通過應用ControlTemplate添加了按鈕(和標題文本)。問題是,我沒有找到一種方法來觸發MyCustomCommand單擊按鈕時。我最終想要實現的是打開一個Popup或ContextMenu,我可以在ListView中選擇哪些列應該可見。WPF:綁定到來自ControlTemplate的命令

這裏是我的模板來源:

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

注意綁定到MyListView中的DependencyProperty的HeaderTitle。這按預期工作。爲什麼它不像命令一樣工作?任何線索如何使這項工作?

回答

2

我不確定這是否正確的方法來做到這一點。這是一個有點難以閱讀註釋的源代碼,所以我寫這條回覆作爲答案...

這裏是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}" /> 
6

你應該做的包裝屬性命令靜態啓動和使用

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

一般來說,你只需要一個ICommand財產,如果該命令被設置爲不同的值上的每個實例(如按鈕)或如果它像ViewModel上的DelegateCommand/RelayCommand。您還應該刪除getter中的所有額外代碼,而是在內聯或靜態構造函數中初始化命令,並在控件的實例構造函數中連接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)); 
} 
+0

謝謝很多。這解決了我的情況:)現在我可以在命令執行時打開一個Popup。 – 2010-10-06 12:26:11

+0

我遇到了一個新問題...觸發命令的按鈕只能在窗口的MyListView的第一個實例中使用(啓用)。它與關鍵字Static有什麼關係:Command = {x:Static local:MyListView。MyCustomCommand} – 2010-10-07 10:56:32

+0

當命令的CanExecute爲false或命令沒有附加Execute處理程序時,帶命令的按鈕被禁用。確保CanExecute中沒有任何奇怪的事情發生,並且CommandBinding正在每個ListView實例上設置,而不是靜態的上下文中,這隻會影響第一個ListView。 – 2010-10-07 11:39:47