WPF - установить фокус при нажатии кнопки - без кода - PullRequest
23 голосов
/ 05 февраля 2010

Есть ли способ установить 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 чтобы сосредоточиться на textBox "txtName"?

Я пытаюсь найти способ сделать что-то подобное, используя строгий MVVM.Если это то, что не должно быть сделано через XAML (в MVVM), тогда это нормально.Но я хотел бы увидеть некоторую документацию о том, как она вписывается в шаблон MVVM, делая это вне XAML.

Ответы [ 7 ]

30 голосов
/ 06 февраля 2010

Рассматривали ли вы использование прикрепленного поведения. Они просты в реализации и использовании 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" />
15 голосов
/ 05 февраля 2010

Я не близко к визуальной студии, поэтому я не могу попробовать это прямо сейчас, но, черт побери, вы сможете сделать что-то вроде этого:

FocusManager.FocusedElement="{Binding ElementName=txtName}">

Edit:

Существует следующий вопрос (задаваемый недавно) об этом здесь: Как настроить автофокус только в xaml? , который содержит этот метод, и несколько разных идей о том, как его использовать.

10 голосов
/ 02 марта 2011

Вы также можете использовать поведение 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 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.

Надеюсь, это кому-нибудь поможет.

4 голосов
/ 21 июня 2015

вам нужно TriggerAction, чтобы вызвать метод Focus () для нужного элемента управления.

public class SetFocusTrigger : TargetedTriggerAction<Control>
{
 protected override void Invoke(object parameter)
 {
    if (Target == null) return;

    Target.Focus();
 }
}

Чтобы установить фокус на Control, вы помещаете коллекцию Triggers после 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>
1 голос
/ 05 февраля 2010

Это то, что вы хотите?

    <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
    }
0 голосов
/ 26 октября 2018

Посмотрите, используете ли вы какой-либо Диспетчер, тогда это будет полезно, но это короткий трюк, который я использовал в своем коде. Просто используйте событие Loaded в вашем XAML и создайте новый обработчик. В этот обработчик вставьте этот код и бинго! ты готов идти

Ваше загруженное событие с некоторыми аргументами здесь ...

{
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, new System.Action(() => {
        The element to be focused goes here......
    }));
}

PS: Требуется Windows. Потоки, если вы не знали;)

0 голосов
/ 12 июня 2015

Это то же самое, что и решение Яна Оукса, но я внес несколько небольших изменений.

  1. Тип кнопки может быть более общим, а именно ButtonBase, для обработки большего количества случаев, например ToggleButton.
  2. Тип цели также может быть более общим, а именно UIElement. Технически, это может быть IInputElement, я полагаю.
  3. Я сделал обработчик событий статическим, чтобы он не генерировал закрытие среды выполнения каждый раз. Чтобы он оставался статичным, я переместил его из лямбды.

Большое спасибо Яну.


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}}" />

Обратите внимание, что событие может нацеливать / фокусировать саму кнопку-инициатор.

...