2010-10-06 11 views
6

Sto tentando di aggiungere un pulsante a un oggetto ListView personalizzato (MyListView) che attiva un comando (MyCustomCommand) definito in MyListView. Ho aggiunto il pulsante (e un testo del titolo) applicando un ControlTemplate. Il problema è che non ho trovato un modo per attivare MyCustomCommand quando si fa clic sul pulsante. Quello che alla fine voglio ottenere è aprire un Popup o ContextMenu in cui posso selezionare quali colonne dovrebbero essere visibili in ListView.WPF: associa il comando a ControlTemplate

Ecco la mia fonte modello:

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

Ecco la definizione per 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; } 
} 

E qui è il codice XAML che crea una semplice istanza di 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> 

Notare HeaderTitle che è associato a DependencyProperty in MyListView. Funziona come previsto. Perché non funziona allo stesso modo con i comandi? Qualche idea su come fare questo lavoro?

risposta

2

Non sono sicuro se questo è il modo corretto per farlo. È un po 'difficile da leggere il codice sorgente nei commenti, così ho scrivere questa risposta come una risposta ...

Qui è il costruttore di MyListView + i metodi di rilegatura di comando:

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

Gli attacchi non sono impostati in un contesto statico. Le uniche cose che sono statici sono il DependencyProperty per il comando e il comando stesso:

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

private static RoutedCommand showColumnPickerCommand; 

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

Il comando deve essere statico a in grado di legarsi ad esso dal XAML in questo modo:

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

Si dovrebbe iniziare con la proprietà wrapper per il comando statico e utilizzare

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

Generalmente si desidera una proprietà ICommand solo se il comando è stato impostato su un valore diverso su ogni istanza (come Button) o se è qualcosa come un DelegateCommand/RelayCommand su un ViewModel. Dovresti anche rimuovere tutto il codice aggiuntivo nel getter e invece inizializzare il comando sia in linea o nel costruttore statico e connettere CommandBinding nel costruttore dell'istanza del controllo.

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

* * UPDATE

Il RoutedCommand stesso deve essere dichiarato come statico. Le proprietà dell'istanza di ICommand sono utili quando un utente esterno del tuo controllo sta passando un comando da eseguire, che non è quello che vuoi qui. Non c'è nemmeno bisogno di un DP qui e quello che stai usando è dichiarato in modo errato - per essere utilizzabili hanno bisogno di avere proprietà wrapper di istanza con GetValue/SetValue.

public static RoutedCommand ShowColumnPickerCommand 
{ 
    get; private set; 
} 

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

Grazie Un sacco. Questo ha risolto il mio caso :) Ora posso aprire un Popup quando il comando viene eseguito. –

+0

Ho incontrato un nuovo problema ... Il pulsante per attivare il comando è disponibile (abilitato) solo nella prima istanza di MyListView in una finestra. Ha qualcosa a che fare con la parola chiave Static in: Command = {x: Static local: MyListView.MyCustomCommand} –

+0

I pulsanti con comandi vengono disabilitati quando CanExecute del comando è falso oppure il comando non ha un gestore Execute collegato. Assicurati di non avere nulla di strano con CanExecute e che CommandBinding sia impostato su ogni istanza di ListView e non in un contesto statico che influenzi solo il primo. –

Problemi correlati