2010-10-06 20 views
6

Próbuję dodać przycisk do niestandardowego ListView (MyListView), który uruchamia polecenie (MyCustomCommand) zdefiniowane w MyListView. Dodałem przycisk (i tekst tytułu), stosując aplikację ControlTemplate. Problem polega na tym, że nie znalazłem sposobu na wywołanie MyCustomCommand po kliknięciu przycisku. W końcu chciałbym otworzyć menu kontekstowe lub menu kontekstowe, w którym mogę wybrać, które kolumny powinny być widoczne w widoku listy.WPF: Bind to command from ControlTemplate

Oto moje źródło szablon:

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

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

A oto XAML, który tworzy prostą instancję 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> 

Uwaga: nagłówekTytuł, który jest powiązany z DependencyProperty w MyListView. Działa to zgodnie z oczekiwaniami. Dlaczego nie działa tak samo z poleceniami? Jakieś wskazówki, jak to zrobić?

Odpowiedz

2

Nie jestem pewien, czy jest to właściwy sposób, aby to zrobić. Jest to trochę trudne do odczytania kodu źródłowego w komentarzach, więc piszę tę odpowiedź jako odpowiedź ...

Oto konstruktor MyListView + metod wiążących poleceń:

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

Wiązania nie są ustawione w statycznym kontekście. Jedyne rzeczy, które są statyczne jesteś DependencyProperty na polecenie, a samą komendę:

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

private static RoutedCommand showColumnPickerCommand; 

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

Polecenie musi być statyczna, aby móc powiązać go z XAML jak poniżej:

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

Należy zacząć od właściwość otoki dla polecenia statycznej i używać

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

Generalnie chcą tylko właściwość ICommand jeżeli polecenie jest ustawiony na inną wartość w każdym przypadku (jak przycisk) lub jeśli jest to coś w stylu DelegateCommand/RelayCommand na ViewModel. Powinieneś także usunąć cały dodatkowy kod z gettera i zamiast tego zainicjować polecenie inline lub w konstruktorze statycznym i połączyć CommandBinding w konstruktorze instancji kontrolki.

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

* * UPDATE

Sam RoutedCommand powinien być zadeklarowany jako statyczny. Właściwości instancji ICommand są dobre, gdy zewnętrzny użytkownik kontrolki przekazuje komendę do wykonania, co nie jest tym, czego potrzebujesz w tym miejscu. Nie ma tu również potrzeby DP, a ten, którego używasz, jest deklarowany niepoprawnie - aby był użyteczny, musi mieć właściwości wrapperu instancji za pomocą GetValue/SetValue.

public static RoutedCommand ShowColumnPickerCommand 
{ 
    get; private set; 
} 

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

Dzięki dużo. To rozwiązało moją sprawę :) Teraz mogę otworzyć wyskakujące okienko po wykonaniu polecenia. –

+0

Wystąpił nowy problem ... Przycisk uruchamiający polecenie jest dostępny tylko (włączony) w pierwszym wystąpieniu MyListView w oknie. Czy ma to coś wspólnego ze słowem kluczowym Static w: Command = {x: Static local: MyListView.MyCustomCommand} –

+0

Przyciski z komendami są wyłączane, gdy polecenie CanExecute ma wartość false lub polecenie nie zawiera dołączonej procedury obsługi Execute. Upewnij się, że nie dzieje się nic dziwnego z CanExecute i że CommandBinding jest konfigurowany na każdej instancji ListView, a nie w statycznym kontekście, który będzie miał wpływ tylko na pierwszy. –

Powiązane problemy