2011-01-17 14 views
15

Jestem zainteresowany tworzeniem poleceń, które są dostępne z dowolnego miejsca w mojej aplikacji WPF.Polecenia WPF, jak zadeklarować polecenia poziomu aplikacji?

Chciałbym im pracować w taki sam sposób jak Cut, Copy, Paste i innych poleceń poziomu aplikacji, tj:

<Button Command="Paste" /> 

ja mogłem CommandBindings założonym edytorów instancji aplikacji, ale że właściwość nie jest dostępna.

Jak to zrobić?

Najlepszą udało mi się do tej pory stworzyć zestaw poleceń w oknie najwyższego poziomu, a następnie korzystać z nich tak ...:

<Button Command="{x:Static namespace::MainWindow.CommandName}" /> 

który pracuje, ale jest oczywiście ściśle sprzężone, i tak bardzo kruche.

Odpowiedz

31

Możesz skonfigurować CommandBindings dla "All Windows" swojej aplikacji WPF i implementować procedury obsługi komend w klasie Application.

Najpierw utwórz klasę kontenera poleceń statycznych. Na przykład:

namespace WpfApplication1 
{ 
    public static class MyCommands 
    { 
     private static readonly RoutedUICommand doSomethingCommand = new RoutedUICommand("description", "DoSomethingCommand", typeof(MyCommands)); 

     public static RoutedUICommand DoSomethingCommand 
     { 
      get 
      { 
       return doSomethingCommand; 
      } 
     } 
    } 
} 

Następnie ustaw własne polecenie na Button.Command w ten sposób.

<Window x:Class="WpfApplication1.MainWindow" 
     ... 
     xmlns:local="clr-namespace:WpfApplication1"> 
    <Grid> 
     ... 
     <Button Command="local:MyCommands.DoSomethingCommand">Execute</Button> 
    </Grid> 
</Window> 

Na koniec zaimplementuj procedurę obsługi niestandardowego polecenia w klasie Aplikacja.

namespace WpfApplication1 
{ 

    public partial class App : Application 
    { 
     public App() 
     { 
      var binding = new CommandBinding(MyCommands.DoSomethingCommand, DoSomething, CanDoSomething); 

      // Register CommandBinding for all windows. 
      CommandManager.RegisterClassCommandBinding(typeof(Window), binding); 
     } 

     private void DoSomething(object sender, ExecutedRoutedEventArgs e) 
     { 
      ... 
     } 

     private void CanDoSomething(object sender, CanExecuteRoutedEventArgs e) 
     { 
      ... 
      e.CanExecute = true; 
     } 
    } 
} 
+0

Thanks Shou, ja spróbuję. Zakładam, że mogę używać nowych nazw poleceń, np. 'ApplicationCommands.MyCommand'?Jeśli nie, to nie odpowiada na moje pytanie. – ocodo

+0

Możesz także użyć poleceń niestandardowych. –

+0

Zmień przykład, aby użyć niestandardowego polecenia, a nie Wklej. Nie mogę znaleźć żadnego innego odniesienia do dodawania nowych poleceń do 'ApplicationCommands', czy możesz podać link? - Chciałbyś również pokazać użycie XAML, szczególnie jeśli różni się od '

2

przypadku próby zdefiniowania CommandBindings lub InputBindings jako zasobów w App.xaml, można zauważyć, że nie można z nich korzystać, ponieważ XAML nie pozwalają na skorzystanie albo:

<Window ... CommandBindings="{StaticResource commandBindings}"> 

lub ustaw powiązania poleceń z ustawiaczem stylu:

<Setter Property="CommandBindings" Value="{StaticResource commandBindings}"> 

ponieważ żadna z tych właściwości nie ma "ustawionego" akcesora. Używając idei w this post, wymyśliłem czysty sposób wykorzystania zasobów z App.xaml lub dowolnego innego słownika zasobów.

Najpierw trzeba określić swoje powiązania polecenia i przypisania wejściowych pośrednio, jak każdy inny zasób:

<InputBindingCollection x:Key="inputBindings"> 
     <KeyBinding Command="Help" Key="H" Modifiers="Ctrl"/> 
    </InputBindingCollection> 
    <CommandBindingCollection x:Key="commandBindings"> 
     <CommandBinding Command="Help" Executed="CommandBinding_Executed"/> 
    </CommandBindingCollection> 

a następnie zwrócić się do nich z XAML z innej klasy:

<Window ...> 
    <i:Interaction.Behaviors> 
     <local:CollectionSetterBehavior Property="InputBindings" Value="{StaticResource inputBindings}"/> 
     <local:CollectionSetterBehavior Property="CommandBindings" Value="{StaticResource commandBindings}"/> 
    </i:Interaction.Behaviors> 
    ... 
</Window> 

CollectionSetterBehavior to zachowanie wielokrotnego użytku, które nie "ustawia" właściwości na jego wartość, ale zamiast tego usuwa kolekcję i ponownie ją wypełnia. Tak więc kolekcja się nie zmienia, tylko jej zawartość.

Oto źródło dla zachowania:

public class CollectionSetterBehavior : Behavior<FrameworkElement> 
{ 
    public string Property 
    { 
     get { return (string)GetValue(PropertyProperty); } 
     set { SetValue(PropertyProperty, value); } 
    } 

    public static readonly DependencyProperty PropertyProperty = 
     DependencyProperty.Register("Property", typeof(string), typeof(CollectionSetterBehavior), new UIPropertyMetadata(null)); 

    public IList Value 
    { 
     get { return (IList)GetValue(ValueProperty); } 
     set { SetValue(ValueProperty, value); } 
    } 

    public static readonly DependencyProperty ValueProperty = 
     DependencyProperty.Register("Value", typeof(IList), typeof(CollectionSetterBehavior), new UIPropertyMetadata(null)); 

    protected override void OnAttached() 
    { 
     var propertyInfo = AssociatedObject.GetType().GetProperty(Property); 
     var property = propertyInfo.GetGetMethod().Invoke(AssociatedObject, null) as IList; 
     property.Clear(); 
     foreach (var item in Value) property.Add(item); 
    } 
} 

Jeśli nie są zaznajomieni z zachowaniami, najpierw dodaj nazw:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 

i dodać odpowiednie odniesienie do projektu.

+0

Pokaż, w jaki sposób będziesz używać tych poleceń w XAML, np. '

6

członkowie StackOverflow pomógł mi tak wiele czasu, że teraz zdecydować, aby przyczynić się i dzielić ;-)

podstawie odpowiedzi Shou Takenaka, oto moja realizacja.

Moje zainteresowanie polegało na wyprodukowaniu tylko jednego pliku wielokrotnego użytku .


pierwsze tworzyć klasy polecenie (polecenia) pojemnika

namespace Helpers 
{ 
    public class SpecificHelper 
    { 
     private static RoutedUICommand _myCommand = new RoutedUICommand("myCmd","myCmd", typeof(SpecificHelper)); 
     public static RoutedUICommand MyCommand { get { return _myCommand; } } 

     static SpecificHelper() 
     { 
      // Register CommandBinding for all windows. 
      CommandManager.RegisterClassCommandBinding(typeof(Window), new CommandBinding(MyCommand, MyCommand_Executed, MyCommand_CanExecute)); 
     } 

     // TODO: replace UIElement type by type of parameter's binded object 
     #region MyCommand 
     internal static void MyCommand_Executed(object sender, ExecutedRoutedEventArgs e) 
     { 
      if (!verifType<UIElement>(e.Parameter)) return; 

      e.Handled = true; 
      // TODO : complete the execution code ... 
     } 

     internal static void SelectAll_CanExecute(object sender, CanExecuteRoutedEventArgs e) 
     { 
      if (!verifType<UIElement>(e.Parameter)) return; 

      e.CanExecute = true; 
      var item = (e.Parameter as UIElement); 
      // TODO : complete the execution code ... 
     } 
     #endregion 

     private static bool verifType<T>(object o) 
     { 
      if (o == null) return false; 
      if (!o.GetType().Equals(typeof(T))) return false; 
      return true; 
     } 
    } 
} 

Następnie zadeklarować zasobu App.xaml:

<Application x:Class="Helper.App" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:h="clr-namespace:Helpers" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      mc:Ignorable="d" 
      StartupUri="MainWindow.xaml" > 
    <Application.Resources> 
     <h:SpecificHelper x:Key="sh" /> 
    </Application.Resources> 
</Application> 

Ponadto, łączą dowolną właściwość komendy do właściwości zasobu aplikacji:

<Button Content="Click to execute my command" 
     Command="{Binding Source={StaticResource sh}, Path=MyCommand}" 
     CommandParameter="{Binding ElementName=myElement}" /> 

to wszystko ludzie :-)

2

mi się nie podoba złożoność innych rozwiązań, ale po kilku godzinach badań I okazało się, że jest naprawdę proste.

Najpierw skonfiguruj swoje polecenie tak, jak zwykle, ale dodaj statyczną właściwość dla WPF, aby uzyskać instancję twojego polecenia.

class MyCommand : ICommand 
{ 
    // Singleton for the simple cases, may be replaced with your own factory if needed. 
    static MyCommand() 
    { 
     Instance = new MyCommand(); 
    } 
    public static ICommand Instance { get; private set; } 

    public bool CanExecute(object parameter) 
    { 
     return true; // TODO: Implement 
    } 

    public event EventHandler CanExecuteChanged; 

    public void Execute(object parameter) 
    { 
     // TODO: Implement  
    } 
} 

Dodaj odwołanie do przestrzeni nazw polecenia w XAML (ostatni wiersz), podobnie jak to:

<Window 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:commands="clr-namespace:MyProject.Commands">  

Następnie wystarczy odwołać swoje właściwości statycznej w XAML tak:

<Button Content="Button" Command="commands:MyCommand.Instance" /> 
2

Zadeklaruj poziom CommandBinding na poziomie Application, skąd można go ponownie użyć wszędzie.

<Application.Resources>  
    <CommandBinding x:Key="PasteCommandKey" Command="ApplicationCommands.Paste" CanExecute="CommandBinding_CanExecute_1"/> 
</Application.Resources> 

W pliku App.xaml.cs zdefiniować odpowiednie teleskopowe:

private void CommandBinding_CanExecute_11(object sender, System.Windows.Input.CanExecuteRoutedEventArgs e) 
    { 
     e.CanExecute = false; 
    } 

wykorzystania

W każdym pliku XAML, użyj go jak poniżej:

<RichTextBox x:Name="Rtb1" ContextMenuOpening="Rtb1_ContextMenuOpening_1" FontSize="15" Margin="10,10,10,-73">    
     <RichTextBox.CommandBindings> 
      <StaticResourceExtension ResourceKey="PasteCommandKey"/> 
     </RichTextBox.CommandBindings> 
+1

Biorąc pod uwagę wyjaśnienia i jakość już opublikowanych odpowiedzi. Twoja odpowiedź naprawdę nie dodaje wartości. Unikaj umieszczania kodu bez wyjaśnienia. Zalecam edycję odpowiedzi, aby najpierw wyjaśnić, a na drugim pokaż kod. Dziękuję Ci. – ocodo

+0

Ta bardzo konkretna odpowiedź bardzo mi pomogła. Nikt inny nie powiedział, że można umieścić '' wewnątrz ''. @ocodo Twój komentarz jest nieprawidłowy. – Endrju

+0

@Endrju - proszę spojrzeć na daty i edytować historię przed komentarzem – ocodo

Powiązane problemy