有没有办法使用WPF Focus
将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
是否有办法专注于textBox“txtName”?
我正在尝试使用严格的MVVM找到这样做的方法。如果这是不应该通过XAML(在MVVM中)完成的,那么这很好。但我希望看到一些文档,说明它如何适合在XAML之外的MVVM模式。
答案 0 :(得分:30)
您是否考虑过使用附加行为?它们易于实现并使用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" />
答案 1 :(得分:14)
我不在视觉工作室附近所以我现在不能尝试这个,但是在我的头脑中,你应该能够做到这样的事情:
FocusManager.FocusedElement="{Binding ElementName=txtName}">
编辑:
此处有一个关于此问题的后续问题(最近询问):How to set autofocus only in xaml?包含此方法,以及有关如何使用它的一些不同想法。
答案 2 :(得分: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继承的任何控件。
希望这有助于某人。
答案 3 :(得分: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>
答案 4 :(得分: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
}
答案 5 :(得分:0)
这与Ian Oakes的解决方案相同,但我做了一些小改动。
ButtonBase
,以处理更多情况,例如ToggleButton
。UIElement
。从技术上讲,我想这可能是IInputElement
。非常感谢伊恩。
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}}" />
请注意,事件可以定位/聚焦原始按钮本身。
答案 6 :(得分:0)
看看是否正在使用任何Dispatcher,这将很有帮助,但这是我在代码中使用的一个简单技巧。只需在XAML中使用Loaded事件并创建一个新的处理程序即可。在该处理程序中粘贴此代码和宾果游戏!你准备好了
您加载的事件带有一些参数...
{
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, new System.Action(() => {
The element to be focused goes here......
}));
}
PS:它需要Windows。如果您不知道,请执行线程;)