c# - eventos - WPF: configure el enfoque cuando se hace clic en un botón: sin código detrás
estilos para botones wpf (6)
¿Es esto lo que quieres?
<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>
do#:
public void MoveFocusOnClick(object sender, RoutedEventArgs e)
{
Keyboard.Focus(txtName); // Or your own logic
}
¿Hay alguna manera de establecer el Focus
de un control a otro usando el Trigger
WPF?
Como el siguiente ejemplo:
<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>
¿Hay alguna manera para que EventTrigger
concentre en el cuadro de texto "txtName"?
Estoy tratando de encontrar la manera de hacer algo como esto usando un MVVM estricto. Si esto es algo que no debe hacerse a través del XAML (en MVVM), entonces está bien. Pero me gustaría ver algún tipo de documentación sobre cómo encaja en el patrón MVVM hacerlo fuera del XAML.
¿Has considerado usar un comportamiento adjunto? Son simples de implementar y usan AttachedProperty''s. Aunque todavía requiere código, este código se abstrae en una clase y se reutiliza. Pueden eliminar la necesidad de ''código detrás'' y a menudo se usan con el patrón MVVM.
Pruebe este y vea si funciona para usted.
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();
}
};
}
}
}
Y luego en tu XAML haz algo como ...
<Button
Content="Click Me!"
local:EventFocusAttachment.ElementToFocus="{Binding ElementName=textBox}"
/>
<TextBox x:Name="textBox" />
Esto es lo mismo que la solución de Ian Oakes, pero hice un par de cambios menores.
- El tipo de botón puede ser más general, es
ButtonBase
,ButtonBase
, para manejar más casos, comoToggleButton
. - El tipo de objetivo también puede ser más general, es decir,
UIElement
. Técnicamente, esto podría serIInputElement
, supongo. - Hice el controlador de eventos estático para que no genere un cierre de tiempo de ejecución cada vez. Para asegurarme de que permanece estático, lo saqué de una lambda.
Muchas gracias a 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();
}
};
El uso es básicamente el mismo que el anterior:
<ToggleButton z:EventFocusAttachment.Target="{Binding RelativeSource={RelativeSource Self}}" />
Tenga en cuenta que el evento puede enfocar / enfocar el botón de origen.
No estoy cerca de Visual Studio, así que no puedo probar esto ahora, pero fuera de mi cabeza, deberías ser capaz de hacer algo como esto:
FocusManager.FocusedElement="{Binding ElementName=txtName}">
Editar:
Hay una pregunta de seguimiento (más recientemente) sobre esto aquí: ¿Cómo establecer el enfoque automático solo en xaml? que contiene este método, y algunas ideas diferentes sobre cómo usarlo.
También podría usar un Comportamiento 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());
}
Aquí está el XAML para usar el comportamiento.
Incluir espacios de nombres:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfApplication1"
Adjunte Comportamiento de WPF al botón y enlace el elemento al que desea establecer el foco:
<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"/>
De esta forma, no tiene código y es reutilizable en cualquier control que herede de ButtonBase.
Espero que esto ayude a alguien.
necesita un TriggerAction
para invocar el método Focus () en el control deseado.
public class SetFocusTrigger : TargetedTriggerAction<Control>
{
protected override void Invoke(object parameter)
{
if (Target == null) return;
Target.Focus();
}
}
Para tener el foco establecido en un Control, coloca una colección de Triggers después de su LayoutRoot (o cualquier control realmente), seleccione el evento como desencadenador y seleccione SetFocusTrigger como la clase para ejecutar. En la declaración SetFocusTrigger, coloca el nombre del control que desea que reciba el foco utilizando la propiedad 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>