26

有没有办法Focus使用 WPF 从一个控件设置到另一个控件Trigger

像下面的例子:

<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 之外执行它。

4

7 回答 7

35

您是否考虑过使用附加行为。它们很容易实现和使用 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" />
于 2010-02-06T11:30:15.287 回答
17

我不在视觉工作室附近,所以我现在不能真正尝试这个,但在我的脑海中,你应该能够做这样的事情:

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

编辑:

这里有一个后续问题(最近被问到):How to set autofocus only in xaml? 其中包含此方法,以及有关如何使用它的一些不同想法。

于 2010-02-05T01:00:40.777 回答
10

您还可以使用 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 的控件上重用。

希望这可以帮助某人。

于 2011-03-01T23:42:08.933 回答
4

您需要TriggerAction在所需控件上调用 Focus() 方法。

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

    Target.Focus();
 }
}

要将焦点设置为 Control ,请在 LayoutRoot (或任何控件)之后放置一个 Triggers 集合,选择事件作为触发器,然后选择 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>
于 2015-06-21T04:59:43.760 回答
1

这是你想要的吗?

    <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
    }
于 2010-02-05T06:26:24.577 回答
1

这与 Ian Oakes 的解决方案相同,但我做了一些小改动。

  1. 按钮类型可以更通用,即ButtonBase处理更多的情况,比如ToggleButton
  2. 目标类型也可以更通用,即UIElement. 从技术上讲,这可能是IInputElement,我想。
  3. 将事件处理程序设为静态,这样每次使用时它都不会生成运行时闭包。
  4. [编辑:2019] 更新为使用空条件和 C#7 表达式主体语法。

非常感谢伊恩。


public sealed class EventFocusAttachment
{
    public static UIElement GetTarget(ButtonBase b) => (UIElement)b.GetValue(TargetProperty);

    public static void SetTarget(ButtonBase b, UIElement tgt) => b.SetValue(TargetProperty, tgt);

    public static readonly DependencyProperty TargetProperty = DependencyProperty.RegisterAttached(
            "Target",
            typeof(UIElement),
            typeof(EventFocusAttachment),
            new UIPropertyMetadata(null, (b, _) => (b as ButtonBase)?.AddHandler(
                ButtonBase.ClickEvent,
                new RoutedEventHandler((bb, __) => GetTarget((ButtonBase)bb)?.Focus()))));
};

用法与上面基本相同:

<ToggleButton z:EventFocusAttachment.Target="{Binding RelativeSource={RelativeSource Self}}" />

请注意,该事件可以定位/聚焦原始按钮本身。

于 2015-06-12T00:25:39.530 回答
0

看看您是否使用任何 Dispatcher 会有所帮助,但这是我在代码中使用的一个小技巧。只需在 XAML 中使用 Loaded 事件并创建一个新的处理程序。在该处理程序中粘贴此代码和宾果游戏!你准备好了

您加载的事件在这里带有一些参数...

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

PS:它需要Windows。线程如果你不知道;)

于 2018-10-26T06:53:03.843 回答