Est-il possible de définir Focus
d'un contrôle à un autre à l'aide de 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>
Existe-t-il un moyen pour que EventTrigger
se concentre sur la zone de texte "txtName"?
J'essaie de trouver le moyen de faire quelque chose comme ça en utilisant un MVVM strict. Si c'est quelque chose qui ne devrait pas être fait via le XAML (dans MVVM), alors c'est très bien. Mais j'aimerais voir une sorte de documentation sur la manière dont cela s'insère dans le modèle MVVM en dehors du XAML.
Avez-vous envisagé d'utiliser un comportement attaché. Ils sont simples à mettre en œuvre et à utiliser AttachedProperty. Bien qu'il ait encore besoin de code, ce code est extrait d'une classe et réutilisé. Ils peuvent éliminer le besoin de "code derrière" et sont souvent utilisés avec le modèle MVVM.
Essayez celui-ci et voyez si cela fonctionne 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, faites quelque chose comme ...
<Button
Content="Click Me!"
local:EventFocusAttachment.ElementToFocus="{Binding ElementName=textBox}"
/>
<TextBox x:Name="textBox" />
Je ne suis pas près du studio visuel, donc je ne peux pas vraiment essayer cela pour le moment, mais vous devriez pouvoir faire quelque chose comme ceci:
FocusManager.FocusedElement="{Binding ElementName=txtName}">
Modifier:
Il y a une question complémentaire (posée plus récemment) à ce sujet ici: Comment définir l'autofocus uniquement dans xaml? qui contient cette méthode et quelques idées différentes sur son utilisation.
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 code XAML pour utiliser le comportement.
Inclure les espaces de noms:
xmlns:i="http://schemas.Microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfApplication1"
Attachez le comportement WPF au bouton et liez l'élément sur lequel 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"/>
Donc, de cette façon, vous n'avez pas de code derrière et il est réutilisable sur tout contrôle hérité de ButtonBase.
J'espère que ça aide quelqu'un.
vous avez besoin d'une TriggerAction
pour appeler la méthode Focus () sur le contrôle souhaité.
public class SetFocusTrigger : TargetedTriggerAction<Control>
{
protected override void Invoke(object parameter)
{
if (Target == null) return;
Target.Focus();
}
}
Pour que le focus soit défini sur un contrôle, vous placez une collection Triggers après votre LayoutRoot (ou tout contrôle en réalité), sélectionnez l'événement en tant que déclencheur, puis sélectionnez SetFocusTrigger en tant que classe à exécuter. Dans la déclaration SetFocusTrigger, vous indiquez le nom du contrôle dont vous souhaitez recevoir le focus à l'aide de 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 ce 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
}
Regardez si vous utilisez un Dispatcher, ce serait utile, mais c’est une astuce que j’ai utilisée dans mon code. Utilisez simplement l'événement Loaded dans votre XAML et créez un nouveau gestionnaire. Dans ce gestionnaire, collez ce code et le bingo! tu es prêt à partir
Votre événement chargé avec quelques arguments ici ...
{
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, new System.Action(() => {
The element to be focused goes here......
}));
}
PS: Il nécessite Windows. Enfiler si vous ne saviez pas;)
C’est la même chose que la solution de Ian Oakes, mais j’ai apporté quelques modifications mineures.
ButtonBase
, pour traiter plusieurs cas, tels que ToggleButton
.UIElement
. Techniquement, cela pourrait être IInputElement
, je suppose.Merci beaucoup à 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'utilisation est fondamentalement la 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.