WPF - установить фокус при нажатии кнопки - нет кода позади
есть ли способ установить Focus
от одного элемента управления к другому с помощью WPF Trigger
s?
как следующий пример:
<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>
есть ли способ для этого EventTrigger
чтобы сосредоточиться на текстовом поле "txtName"?
Я пытаюсь найти способ сделать что-то подобное, используя строгий MVVM. Если это то, что не должно быть сделано через XAML (в MVVM), то это нормально. Но я хотел бы увидеть какую-то документацию о том, как она вписывается в MVVM шаблон в XAML-код.
6 ответов
вы рассматривали использование прикрепленного поведения. Они просты в реализации и использовании AttachedProperty. Хотя он по-прежнему требует кода, этот код абстрагируется в классе и используется повторно. Они могут устранить необходимость "кода позади" и часто используются с шаблоном MVVM.
попробуйте этот и посмотрите, работает ли он для вас.
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();
}
};
}
}
}
а затем в вашем XAML сделайте что-то вроде...
<Button
Content="Click Me!"
local:EventFocusAttachment.ElementToFocus="{Binding ElementName=textBox}"
/>
<TextBox x:Name="textBox" />
Я не рядом с visual studio, поэтому я не могу попробовать это прямо сейчас, но с моей головы, вы должны быть в состоянии сделать что-то вроде этого:
FocusManager.FocusedElement="{Binding ElementName=txtName}">
изменить:
есть следующий вопрос (заданный недавно) об этом здесь:как установить автофокус только в xaml?, который содержит этот метод, и несколько разных идей о том, как использовать его.
вы также можете использовать поведение 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());
}
вот XAML для использования поведения.
включать пространства имен:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfApplication1"
прикрепите поведение WPF к элементу button и bind, на который вы хотите установить фокус:
<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"/>
таким образом, у вас нет кода, и он повторно используется для любого элемента управления, который наследуется от ButtonBase.
надеюсь, это кому-то поможет.
вам понадобится TriggerAction
для вызова метода Focus () для нужного элемента управления.
public class SetFocusTrigger : TargetedTriggerAction<Control>
{
protected override void Invoke(object parameter)
{
if (Target == null) return;
Target.Focus();
}
}
чтобы установить фокус на элемент управления, поместите коллекцию триггеров после LayoutRoot (или любого элемента управления), выберите событие в качестве триггера и выберите SetFocusTrigger в качестве класса для запуска. В объявлении SetFocusTrigger Укажите имя элемента управления, который требуется получить фокус с помощью свойства 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>
это то, что вы хотите?
<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
}
это то же самое, что и решение Яна Оукса, но я сделал пару незначительных изменений.
- тип может быть более общим, а именно
- целевой тип может быть более общим, а именно
UIElement
. Технически, это может бытьIInputElement
, Я полагаю. - Я сделал обработчик событий статическим, чтобы он не создавал закрытие среды выполнения каждый раз. Чтобы убедиться, что он остается статичным, я вытащил его из лямбда.
ButtonBase
, чтобы обрабатывать больше случаев, таких как ToggleButton
.
большое спасибо Яна.
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();
}
};
использование в основном то же самое, что и выше:
<ToggleButton z:EventFocusAttachment.Target="{Binding RelativeSource={RelativeSource Self}}" />
обратите внимание, что событие может нацеливать / фокусировать саму исходную кнопку.