WPF-set Focus quand un bouton est cliqué - pas de Code derrière
y a-t-il un moyen de passer Focus
d'un contrôle à un autre en utilisant WPF Trigger
s?
comme dans l'exemple suivant:
<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>
y a-t-il un moyen pour ce EventTrigger
de mettre l'accent sur le textBox"txtName"?
j'essaie de trouver le moyen de faire quelque chose comme ça en utilisant le MVVM strict. Si c'est quelque chose qui ne devrait pas être fait via le XAML (en MVVM) alors c'est très bien. Mais je voudrais voir une sorte de documentation sur la façon dont il s'intègre dans le modèle MVVM le faisant en dehors du XAML.
6 réponses
avez-vous envisagé d'utiliser un comportement attaché. Ils sont simples à mettre en œuvre et à utiliser des biens attachés. Bien qu'il nécessite encore du code, ce code est abstrait dans une classe et être réutilisé. Ils peuvent éliminer le besoin "code derrière" et sont souvent utilisés avec le modèle MVVM.
essayez celui-ci et voyez si ça marche pour vous.
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();
}
};
}
}
}
et ensuite dans votre XAML faire quelque chose comme...
<Button
Content="Click Me!"
local:EventFocusAttachment.ElementToFocus="{Binding ElementName=textBox}"
/>
<TextBox x:Name="textBox" />
Je ne suis pas près de visual studio donc je ne peux pas réellement essayer cela maintenant, mais du haut de ma tête, vous devriez être en mesure de faire quelque chose comme ceci:
FocusManager.FocusedElement="{Binding ElementName=txtName}">
Edit:
il y a une question de suivi (posée plus récemment) à ce sujet ici: comment définir autofocus seulement dans xaml? qui contient cette méthode, et quelques idées sur la façon de l'utiliser.
vous pouvez également utiliser un comportement WPF...
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());
}
voici le XAML pour utiliser le comportement.
Inclure des espaces de noms:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfApplication1"
Joindre WPF Comportement de bouton et de lier l'élément que vous souhaitez définir le focus:
<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"/>
ainsi vous n'avez pas de code derrière et il est réutilisable sur n'importe quel contrôle qui hérite de ButtonBase.
J'espère que ça aidera quelqu'un.
vous avez besoin d'un TriggerAction
pour invoquer la méthode Focus() sur le contrôle désiré.
public class SetFocusTrigger : TargetedTriggerAction<Control>
{
protected override void Invoke(object parameter)
{
if (Target == null) return;
Target.Focus();
}
}
pour mettre l'accent sur un contrôle , vous placez une collection de déclencheurs après votre LayoutRoot (ou n'importe quel contrôle), sélectionnez l'événement comme déclencheur, et sélectionnez le Setfocistrigger comme classe à exécuter. Dans la déclaration SetFocusTrigger, vous mettez le nom du contrôle que vous voulez recevoir le focus en utilisant la propriété TargetName.
<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>
C'est ça que tu veux?
<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
}
c'est la même chose que la solution de Ian Oakes, mais j'ai fait quelques changements mineurs.
- le type de bouton peut être plus général, à savoir
ButtonBase
, pour traiter plus de cas, tels queToggleButton
. - le type cible peut aussi être plus général, à savoir
UIElement
. Techniquement , ça pourrait êtreIInputElement
, je suppose. - j'ai fait le gestionnaire d'événements statique de sorte qu'il ne générera pas une fermeture d'exécution à chaque fois. De assurez-vous qu'il reste statique, je l'ai déplacé d'un lambda.
un grand merci à 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();
}
};
L'Usage est essentiellement le même que ci-dessus:
<ToggleButton z:EventFocusAttachment.Target="{Binding RelativeSource={RelativeSource Self}}" />
notez que l'événement peut cibler/focaliser le bouton d'origine lui-même.