C# WPF - 单击按钮时设置焦点 - 没有代码隐藏
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2204063/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF - Set Focus when a button is clicked - No Code Behind
提问by Vaccano
Is there a way to set Focus
from one control to another using WPF Trigger
s?
有没有办法Focus
使用 WPF 从一个控件设置到另一个控件Trigger
?
Like the following example:
像下面的例子:
<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>
Is there a way for this EventTrigger
to put to focus on the textBox "txtName"?
有没有办法EventTrigger
把重点放在文本框“txtName”上?
I am trying to find the way to do something like this using strict MVVM. If this is something that should not be done via the XAML (in MVVM) then that is fine. But I would like to see some kind of documentation as to how it fit in the MVVM pattern doing it outside the XAML.
我正在尝试使用严格的 MVVM 找到执行此类操作的方法。如果这是不应该通过 XAML(在 MVVM 中)完成的事情,那很好。但是我想查看一些关于它如何在 XAML 之外执行它的 MVVM 模式的文档。
采纳答案by Ian Oakes
Have you considered using an attached behaviour. They are simple to implement and use AttachedProperty's. Although it still requires code, this code is abstracted away in a class and be reused. They can eliminate the need 'code behind' and are often used with the MVVM pattern.
您是否考虑过使用附加行为。它们易于实现和使用 AttachedProperty。虽然它仍然需要代码,但这些代码在一个类中被抽象出来并被重用。它们可以消除“代码隐藏”的需要,并且通常与 MVVM 模式一起使用。
Try this one and see if it works for you.
试试这个,看看它是否适合你。
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();
}
};
}
}
}
And then in your XAML do something like...
然后在您的 XAML 中执行类似...
<Button
Content="Click Me!"
local:EventFocusAttachment.ElementToFocus="{Binding ElementName=textBox}"
/>
<TextBox x:Name="textBox" />
回答by caesay
I'm not near visual studio so I can't actually try this right now, but off the top of my head, you should be able to do something like this:
我不在visual studio附近,所以我现在不能真正尝试这个,但是在我的脑海里,你应该能够做这样的事情:
FocusManager.FocusedElement="{Binding ElementName=txtName}">
Edit:
编辑:
There is a followup question (asked more recently) about this here: How to set autofocus only in xaml?which contains this method, and a few different ideas on how to use it.
这里有一个关于这个的后续问题(最近被问到):How to set autofocus only in xaml? 其中包含此方法,以及有关如何使用它的一些不同想法。
回答by mg007
Is this what you want?
这是你想要的吗?
<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#:
C#:
public void MoveFocusOnClick(object sender, RoutedEventArgs e)
{
Keyboard.Focus(txtName); // Or your own logic
}
回答by droidalmatter
You could also use a WPF Behavior...
您还可以使用 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());
}
Here is the XAML to use the behavior.
这是使用该行为的 XAML。
Include namespaces:
包括命名空间:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfApplication1"
Attach WPF Behavior to button and bind element you want to set focus to:
将 WPF Behavior 附加到按钮并绑定要设置焦点的元素:
<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"/>
So this way you have no code behind and it is reusable on any control that inherits from ButtonBase.
所以这样你就没有背后的代码,它可以在任何继承自 ButtonBase 的控件上重用。
Hope this helps someone.
希望这可以帮助某人。
回答by Glenn Slayden
This is the same as Ian Oakes' solution, but I made a couple minor changes.
这与 Ian Oakes 的解决方案相同,但我做了一些小改动。
- The button type can be more general, namely
ButtonBase
, to handle more cases, such asToggleButton
. - The target type can also be more general, namely
UIElement
. Technically, this could beIInputElement
, I suppose. - Made the event handler static so that it won't generate a runtime closure every time this is used.
- [edit: 2019] Updated to use null-conditional and C#7 expression body syntax.
- 按钮类型可以更通用,也就是
ButtonBase
处理更多的情况,比如ToggleButton
。 - 目标类型也可以更通用,即
UIElement
. 从技术上讲,这可能是IInputElement
,我想。 - 将事件处理程序设为静态,以便每次使用时都不会生成运行时闭包。
- [编辑:2019] 更新为使用空条件和 C#7 表达式主体语法。
Many thanks to Ian.
非常感谢伊恩。
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()))));
};
Usage is basically the same as above:
用法与上面基本相同:
<ToggleButton z:EventFocusAttachment.Target="{Binding RelativeSource={RelativeSource Self}}" />
Note that the event can target/focus the originating button itself.
请注意,该事件可以针对/聚焦原始按钮本身。
回答by ar.gorgin
you need a TriggerAction
to invoke the Focus() method on the desired control.
您需要TriggerAction
在所需控件上调用 Focus() 方法。
public class SetFocusTrigger : TargetedTriggerAction<Control>
{
protected override void Invoke(object parameter)
{
if (Target == null) return;
Target.Focus();
}
}
To have the focus set to a Control , you place a Triggers collection after your LayoutRoot (or any control really), select the event as the trigger, and select the SetFocusTrigger as the class to run. In the SetFocusTrigger declaration, you put the name of the control that you want to receive the focus by using the TargetName property.
要将焦点设置为 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>
回答by Yash Joshi
Look if you're using any Dispatcher then it would be helpful but this is a short trick I used in my code. Just use the Loaded event in your XAML and make a new handler. In that handler paste this code and bingo! you're ready to go
看看您是否正在使用任何 Dispatcher,那么它会有所帮助,但这是我在代码中使用的一个简短技巧。只需在 XAML 中使用 Loaded 事件并创建一个新的处理程序。在该处理程序中粘贴此代码和宾果游戏!你准备好了
Your loaded event with some arguments here...
你加载的事件在这里有一些参数......
{
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, new System.Action(() => {
The element to be focused goes here......
}));
}
PS: It requires Windows. Threading if you didn't know ;)
PS:它需要Windows。线程,如果你不知道;)