WPF - Fokus festlegen, wenn eine Schaltfläche geklickt wird - kein Code Behind
-
18-09-2019 - |
Frage
Gibt es eine Möglichkeit Focus
von einem Steuerelement zu einem anderen zu setzen mit WPF Trigger
s?
Wie das folgende 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
auf der Textbox „txtName“ konzentrieren zu setzen?
Ich versuche, den Weg zu finden, so etwas wie dies mit strengen MVVM zu tun. Ist dies etwas, das nicht über das XAML (in MVVM) getan werden soll, dann ist das in Ordnung. Aber ich mag eine Art von Dokumentation, um zu sehen, wie sie passte in dem MVVM Muster außerhalb des XAML zu tun.
Lösung
Haben Sie darüber nachgedacht, ein angeschlossenes Verhalten verwenden. Sie sind einfach zu implementieren und AttachedProperty der Verwendung. Obwohl es immer noch Code erfordert, wird dieser Code in einer Klasse abstrahiert und wiederverwendet werden. Sie können die Notwendigkeit, ‚Code hinter‘ beseitigen und werden häufig mit dem MVVM Muster verwendet.
versuchen diese und sehen, ob es für Sie arbeitet.
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 XAML tut so etwas wie ...
<Button
Content="Click Me!"
local:EventFocusAttachment.ElementToFocus="{Binding ElementName=textBox}"
/>
<TextBox x:Name="textBox" />
Andere Tipps
Ich bin nicht in der Nähe von Visual Studio, so kann ich nicht wirklich dieses Recht versuche jetzt, aber aus der Spitze von meinem Kopf, sollten Sie in der Lage sein, so etwas zu tun:
FocusManager.FocusedElement="{Binding ElementName=txtName}">
Edit:
Es ist ein Followup Frage (fragte jüngerer Zeit) dazu hier: Wie Autofokus nur in xAML festlegen? , die diese Methode enthält, und ein paar andere Ideen, wie es zu benutzen.
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 das XAML, das Verhalten zu verwenden.
Namespaces enthalten:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfApplication1"
Anhängen WPF Verhalten auf Schaltfläche und binden Element Sie Fokus einstellen 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"/>
So diese Weise haben Sie keinen Code hinter und es ist wiederverwendbar auf jeder Kontrolle, die von Button erbt.
Hoffe, das hilft jemand.
Sie benötigen einen TriggerAction
den Focus () -Methode auf die gewünschte Steuerung aufzurufen.
public class SetFocusTrigger : TargetedTriggerAction<Control>
{
protected override void Invoke(object parameter)
{
if (Target == null) return;
Target.Focus();
}
}
den Fokus haben, auf eine Kontrolle setzen, legen Sie eine Trigger Sammlung nach dem LayoutRoot (oder jede Kontrolle wirklich), wählen Sie das Ereignis als Auslöser, und wählen Sie die SetFocusTrigger wie die Klasse zu laufen. In der SetFocusTrigger Erklärung, setzen Sie den Namen der Steuerung, die Sie den Fokus mithilfe der Targetname-Eigenschaft erhalten möchten.
<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>
Ist das, was Sie wollen?
<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
}
Dies ist das gleiche wie Ian Oakes' Lösung, aber ich habe ein paar kleinere Änderungen.
- Die Schaltfläche Typ allgemeiner sein kann, nämlich
ButtonBase
mehr Fälle, wieToggleButton
zu behandeln. - Der Typ Ziel kann auch allgemeinere, nämlich
UIElement
sein. Technisch gesehen, könnte diesIInputElement
, nehme ich an. - Made der Event-Handler statisch, so dass es nicht eine Laufzeit Schließung jedes Mal erzeugen wird diese verwendet wird.
- [edit: 2019]. Aktualisiert null-bedingte zu verwenden und C # 7 Ausdruck Körper Syntax
Vielen Dank an Ian.
public sealed class EventFocusAttachment
{
public static UIElement GetTarget(ButtonBase b) => (UIElement)b.GetValue(TargetProperty);
public static void SetTarget(ButtonBase b, UIElement tgt) => b.SetValue(TargetProperty, tgt);
public static readonly DependencyProperty TargetProperty = DependencyProperty.RegisterAttached(
"Target",
typeof(UIElement),
typeof(EventFocusAttachment),
new UIPropertyMetadata(null, (b, _) => (b as ButtonBase)?.AddHandler(
ButtonBase.ClickEvent,
new RoutedEventHandler((bb, __) => GetTarget((ButtonBase)bb)?.Focus()))));
};
Die Verwendung ist grundsätzlich die gleiche wie oben:
<ToggleButton z:EventFocusAttachment.Target="{Binding RelativeSource={RelativeSource Self}}" />
Beachten Sie, dass die Veranstaltung ausrichten können / fokussieren den Ursprung Schaltfläche selbst.
Sehen Sie, wenn Sie irgendeine Dispatcher verwenden, dann wäre es hilfreich sein, aber dies ist nur ein kurzer Trick, den ich in meinem Code verwendet. Verwenden Sie einfach das Loaded-Ereignis in Ihrem XAML und einen neuen Handler machen. In diesem Handler diesen Code und Bingo einfügen! sind bereit, Sie gehen
Ihre geladene Veranstaltung mit einigen Argumenten hier ...
{
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, new System.Action(() => {
The element to be focused goes here......
}));
}
PS: Es erfordert Windows. Threading, wenn Sie nicht wissen;)