web-dev-qa-db-de.com

WPF - Fokus einstellen, wenn auf eine Schaltfläche geklickt wird

Gibt es eine Möglichkeit, Focus mit WPF Triggers von einem Steuerelement zu einem anderen zu setzen?

Wie im folgenden Beispiel:

<Page
  xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml">
  <Grid>  
    <Grid.RowDefinitions>
      <RowDefinition/>
      <RowDefinition/>
      <RowDefinition/>
    </Grid.RowDefinitions>

    <TextBox Name="txtName"></TextBox>    
    <TextBox Grid.Row="1" Name="txtAddress"></TextBox>
    <Button Grid.Row="2" Content="Finish">
        <Button.Triggers>
            <EventTrigger RoutedEvent="Button.Click">

                <!-- Insert cool code here-->  

            </EventTrigger>
        </Button.Triggers>
    </Button>
  </Grid>
</Page>

Gibt es eine Möglichkeit für diese EventTrigger, sich auf die textBox "txtName" zu konzentrieren?

Ich versuche, den Weg zu finden, um so etwas mit strenger MVVM zu tun. Wenn dies nicht über die XAML (in MVVM) erfolgen soll, ist dies in Ordnung. Ich würde jedoch gerne eine Dokumentation darüber erhalten, wie es in das MVVM-Muster passt, das außerhalb der XAML ausgeführt wird.

22
Vaccano

Haben Sie überlegt, ein angefügtes Verhalten zu verwenden. Sie sind einfach zu implementieren und verwenden AttachedProperty. Obwohl dieser Code immer noch Code erfordert, wird dieser Code in einer Klasse abstrahiert und wiederverwendet. Sie können den Bedarf an „Code dahinter“ beseitigen und werden häufig mit dem MVVM-Muster verwendet.

Probieren Sie es aus und sehen Sie, ob es für Sie funktioniert.

public class EventFocusAttachment
{
    public static Control GetElementToFocus(Button button)
    {
        return (Control)button.GetValue(ElementToFocusProperty);
    }

    public static void SetElementToFocus(Button button, Control value)
    {
        button.SetValue(ElementToFocusProperty, value);
    }

    public static readonly DependencyProperty ElementToFocusProperty =
        DependencyProperty.RegisterAttached("ElementToFocus", typeof(Control), 
        typeof(EventFocusAttachment), new UIPropertyMetadata(null, ElementToFocusPropertyChanged));

    public static void ElementToFocusPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        var button = sender as Button;
        if (button != null)
        {
            button.Click += (s, args) =>
                {
                    Control control = GetElementToFocus(button);
                    if (control != null)
                    {
                        control.Focus();
                    }
                };
        }
    }
}

Und dann in deiner XAML so etwas wie ...

<Button 
    Content="Click Me!" 
    local:EventFocusAttachment.ElementToFocus="{Binding ElementName=textBox}" 
    />
<TextBox x:Name="textBox" />
30
Ian Oakes

Ich bin nicht in der Nähe des visuellen Studios, also kann ich das jetzt nicht wirklich ausprobieren, aber aus meinem Kopf heraus sollten Sie so etwas tun können:

FocusManager.FocusedElement="{Binding ElementName=txtName}">

Bearbeiten:

Hier gibt es eine Folgefrage (in letzter Zeit gestellt): Wie kann man den Autofokus nur in xaml einstellen? welches diese Methode enthält und ein paar verschiedene Ideen, wie man sie benutzt.

14
caesay

Sie können auch ein WPF-Verhalten verwenden ...

    public class FocusElementAfterClickBehavior : Behavior<ButtonBase>
{
    private ButtonBase _AssociatedButton;

    protected override void OnAttached()
    {
        _AssociatedButton = AssociatedObject;

        _AssociatedButton.Click += AssociatedButtonClick;
    }

    protected override void OnDetaching()
    {
        _AssociatedButton.Click -= AssociatedButtonClick;
    }

    void AssociatedButtonClick(object sender, RoutedEventArgs e)
    {
        Keyboard.Focus(FocusElement);
    }

    public Control FocusElement
    {
        get { return (Control)GetValue(FocusElementProperty); }
        set { SetValue(FocusElementProperty, value); }
    }

    // Using a DependencyProperty as the backing store for FocusElement.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FocusElementProperty =
        DependencyProperty.Register("FocusElement", typeof(Control), typeof(FocusElementAfterClickBehavior), new UIPropertyMetadata());
}

Hier ist die XAML, um das Verhalten zu verwenden.

Namespaces einschließen:

xmlns:i="http://schemas.Microsoft.com/expression/2010/interactivity" 
xmlns:local="clr-namespace:WpfApplication1"

Hängen Sie das WPF-Verhalten an ein Schaltflächen- und Bindungselement an, auf das Sie den Fokus setzen möchten: 

<Button Content="Focus" Width="75">
    <i:Interaction.Behaviors>
        <local:FocusElementAfterClickBehavior FocusElement="{Binding ElementName=CheckBoxComboBox, Mode=OneWay}"/>
    </i:Interaction.Behaviors>
</Button>
<ComboBox x:Name="CheckBoxComboBox" HorizontalAlignment="Center" VerticalAlignment="Center" Width="120" Grid.Row="1"/>

Auf diese Weise haben Sie keinen Code hinter sich und können von jedem Steuerelement, das von ButtonBase erbt, wiederverwendet werden.

Hoffe das hilft jemandem.

10
droidalmatter

sie benötigen eine TriggerActionname__, um die Focus () - Methode für das gewünschte Steuerelement aufzurufen.

public class SetFocusTrigger : TargetedTriggerAction<Control>
{
 protected override void Invoke(object parameter)
 {
    if (Target == null) return;

    Target.Focus();
 }
}

Um den Fokus auf ein Steuerelement zu setzen, platzieren Sie eine Trigger-Auflistung nach Ihrem LayoutRoot (oder wirklich einem Steuerelement), wählen das Ereignis als Auslöser aus und wählen den SetFocusTrigger als auszuführende Klasse. In der SetFocusTrigger-Deklaration geben Sie den Namen des Steuerelements ein, für das Sie den Fokus erhalten möchten, indem Sie die TargetName-Eigenschaft verwenden.

<Button x:Name="LayoutRoot" >
<i:Interaction.Triggers>
    <i:EventTrigger EventName="Clicked">
        <local:SetFocusTrigger TargetName="StartHere"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

<TextBox x:Name="StartHere"/>
</Button>
4
ar.gorgin

Ist das was du willst?

    <TextBox Name="txtName"></TextBox>
    <TextBox Grid.Row="1" Name="txtAddress"></TextBox>
    <Button Grid.Row="2" Content="Finish">
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <EventSetter Event="Click" Handler="MoveFocusOnClick" />
            </Style>
        </Button.Style>
        <!--<Button.Triggers>
            <EventTrigger RoutedEvent="Button.Click">
            </EventTrigger>
        </Button.Triggers>-->
    </Button>

c #:

    public void MoveFocusOnClick(object sender, RoutedEventArgs e)
    {
        Keyboard.Focus(txtName); // Or your own logic
    }
1
mg007

Sehen Sie, wenn Sie einen Dispatcher verwenden, wäre dies hilfreich, aber dies ist ein kurzer Trick, den ich in meinem Code verwendet habe. Verwenden Sie einfach das Loaded-Ereignis in Ihrer XAML und erstellen Sie einen neuen Handler. In diesem Handler fügen Sie diesen Code und Bingo ein! Du bist bereit zu gehen

Ihr geladenes Ereignis mit einigen Argumenten hier ...

{
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, new System.Action(() => {
        The element to be focused goes here......
    }));
}

PS: Es erfordert Windows. Einfädeln, wenn du es nicht wusstest;)

0
Yash Joshi

Dies ist die gleiche Lösung wie die von Ian Oakes, aber ich habe ein paar kleinere Änderungen vorgenommen. 

  1. Der Schaltflächentyp kann allgemeiner sein, nämlich ButtonBase, um mehr Fälle zu behandeln, wie ToggleButton.
  2. Der Zieltyp kann auch allgemeiner sein, nämlich UIElement. Technisch könnte dies IInputElement sein, nehme ich an.
  3. Ich habe den Event-Handler statisch gemacht, damit er nicht jedes Mal einen Laufzeitabschluss generiert. Damit es statisch bleibt, habe ich es aus einem Lambda herausgeholt.

Vielen Dank an Ian.


public sealed class EventFocusAttachment
{
    [DebuggerStepThrough]
    public static UIElement GetTarget(ButtonBase b) { return (UIElement)b.GetValue(TargetProperty); }

    [DebuggerStepThrough]
    public static void SetTarget(ButtonBase b, UIElement target) { b.SetValue(TargetProperty, target); }

    public static readonly DependencyProperty TargetProperty =
        DependencyProperty.RegisterAttached("Target",
                                            typeof(UIElement),
                                            typeof(EventFocusAttachment),
                                            new UIPropertyMetadata(null, TargetPropertyChanged));

    public static void TargetPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs _)
    {
        ButtonBase bb;
        if ((bb = o as ButtonBase) != null)
            bb.Click += handler;
    }

    static void handler(Object o, RoutedEventArgs _)
    {
        UIElement target;
        if ((target = GetTarget((ButtonBase)o)) != null)
            target.Focus();
    }
};

Die Verwendung ist im Wesentlichen dieselbe wie oben:

<ToggleButton z:EventFocusAttachment.Target="{Binding RelativeSource={RelativeSource Self}}" />

Beachten Sie, dass das Ereignis die Ursprungsschaltfläche selbst anvisieren bzw. fokussieren kann.

0
Glenn Slayden