Wie kann ich in Silverlight in Dialogen einen Default-Button festlegen?

Veröffentlicht: 02. Jun 2010

Das Problem

Es ist Gang und Gäbe, dass zum Beispiel beim Ausfüllen eines Formulars nur die <Enter>-Taste gedrückt werden muss und eine bestimmte Aktion wird ausgelöst. Dieser How-To-Guide beschreibt, wie man in einer Silverlight-Anwendung einen Default-Button festlegt, der ausgelöst wird, wenn der Benutzer <Enter> drückt.

Die Lösung

  1. Erstellen Sie im Visual Studio 2010 eine neue Silverlight-Anwendung. In diesem Beispiel wird der Projektname DefaultButtonCs verwendet.
  2. Fügen Sie der MainPage.xaml eine TextBox und einen Button hinzu, der ausgelöst werden soll, wenn in der TextBox die <Enter>-Taste gedrückt wird. Geben Sie dem Button den Namen „defaultButton“ und implementieren Sie im EvenHandler des Clicked-Events die Logik, die ausgeführt werden soll, wenn auf den Button gedrückt wird. In diesem Beispiel wird eine MessageBox mit einer Meldung angezeigt.
  3. Fügen Sie dem Projekt einen Verweis auf die System.Windows.Interactivity.dll aus dem Expression SDK hinzu.
  4. Erstellen Sie in einer neuen Datei DefaultButtonTrigger.cs einen Namespace DefaultButtonCs.Triggers
  5. In diesem Namespace erstellen Sie eine Klasse DefaultButtonTrigger, die von der Klasse TargetedTriggerAction<ButtonBase> ableitet.
  6. Implementieren Sie in dieser Klasse zwei private Felder: _peer vom Typ AutomationPeer und _targetedButton vom Typ ButtonBase.
  7. Überschreiben Sie in dieser Klasse die Methoden OnAttached() und OnTargetChanged(...) und implementieren Sie in beiden Fällen folgende Logik, welche die Eigenschaften _peer und _targetedButton füllt.
  8. targetedButton = this.Target;
    if (null == _targetedButton) return;
    
    _peer = FrameworkElementAutomationPeer.FromElement(_targetedButton);
    if (_peer == null)
    {
      _peer = FrameworkElementAutomationPeer.CreatePeerForElement(_targetedButton);
    }  
    		
  9. Überschreiben Sie ebenfalls die Methode Invoke(object parameter). Als Parameter werden beim Aufruf die KeyEventArgs des KeyDown-Events übergeben werden. Überprüfen Sie, ob die <Enter>-Taste gedrückt wurde und lösen Sie auf dem Peer die Invoke()-Methode aus, wenn das dies Fall ist.
  10. KeyEventArgs keyEventArgs = parameter as KeyEventArgs;
    if (null != keyEventArgs && keyEventArgs.Key == Key.Enter)
    {
        if (null != _peer && _peer.IsEnabled())
        {
            IInvokeProvider invokeProvider 
                  =_peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
            invokeProvider.Invoke();
        }
    }
    		
  11. Referenzieren Sie in der MainPage.xaml die XML-Namespaces interactivity aus der Assembly System.Windows.Interactivity und triggers aus dem Namespace DefaultButtonCS.Triggers des Projekts.
  12. Fügen Sie dem TextBox-Element folgendes XAML-Markup hinzu, um einen Trigger für das KeyDown-Event auf den defaultButton einzurichten:
  13. <TextBox>
        <interactivity:Interaction.Triggers>
            <interactivity:EventTrigger EventName="KeyDown">
                <triggers:DefaultButtonTrigger TargetName="defaultButton" /> 
            </interactivity:EventTrigger>
        </interactivity:Interaction.Triggers>
    </TextBox>
    		
  14. Starten Sie das Projekt. Vergleichen Sie das Verhalten, wenn Sie den Button durch einen Mausklick auslösen mit dem Ergebnis, wenn Sie den Fokus in die TextBox setzen und die <Enter>-Taste drücken.

Der Code

MainPage.xaml

<UserControl x:Class="DefaultButtonCs.MainPage"
...
xmlns:interactivity="clr-namespace:System.Windows.Interactivity;
                     assembly=System.Windows.Interactivity"
xmlns:triggers="clr-namespace:DefaultButtonCs.Triggers"
...>
...
<TextBox>
    <interactivity:Interaction.Triggers>
        <interactivity:EventTrigger EventName="KeyDown">
            <triggers:DefaultButtonTrigger TargetName="defaultButton" /> 
        </interactivity:EventTrigger>
    </interactivity:Interaction.Triggers>
</TextBox>
...
    
<Button x:Name="defaultButton" Content="Default-Button" 
        Click="defaultButton_Click"/>
...
</UserControl>

MainPage.xaml.cs

namespace DefaultButtonCs
{
public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();
    }

    private void defaultButton_Click(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("Default-Button gedrückt.");
    }
}
}

DefaultButtonTrigger.cs

...
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using System.Windows.Controls.Primitives;
using System.Windows.Interactivity;

namespace DefaultButtonCs.Triggers
{
public class DefaultButtonTrigger : TargetedTriggerAction<ButtonBase>
{
    private AutomationPeer _peer { get; set; }
    private ButtonBase _targetedButton { get; set; }

    
    protected override void OnAttached()
    {
        base.OnAttached();

        _targetedButton = this.Target;
        if (null == _targetedButton) return;

        _peer = FrameworkElementAutomationPeer.FromElement(_targetedButton);
        if (_peer == null)
        {
            _peer = 
             FrameworkElementAutomationPeer.CreatePeerForElement(_targetedButton);
        }
    }

    protected override void OnTargetChanged(ButtonBase oldTarget, 
                                            ButtonBase newTarget)
    {
        base.OnTargetChanged(oldTarget, newTarget);

        _targetedButton = newTarget;
        if (null == _targetedButton) return;

        _peer = FrameworkElementAutomationPeer.FromElement(_targetedButton);
        if (_peer == null)
        {
            _peer = 
            FrameworkElementAutomationPeer.CreatePeerForElement(_targetedButton);
        }
    }

    protected override void Invoke(object parameter)
    {
        KeyEventArgs keyEventArgs = parameter as KeyEventArgs;

        if (null != keyEventArgs && keyEventArgs.Key == Key.Enter)
        {
            if (null != _peer && _peer.IsEnabled())
            {
                IInvokeProvider invokeProvider = _peer.GetPattern(PatternInterface.Invoke)
                                                                       as IInvokeProvider;
                invokeProvider.Invoke();
            }
        }
    }
}
}

Voraussetzungen

Microsoft Expression SDK
http://www.microsoft.com/downloads/details.aspx?FamilyID=f1ae9a30-4928-411d-970b-e682ab179e17&DisplayLang=de