WPF Focus
sを使用して、あるコントロールから別のコントロールに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を使用してこのようなことを行う方法を見つけようとしています。これが(MVVMの)XAMLを介して実行すべきではない場合、問題ありません。しかし、XAMLの外でそれを実行するMVVMパターンにどのように適合するかについて、ある種のドキュメントが欲しいです。
添付された動作の使用を検討しましたか? 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" />
私はビジュアルスタジオの近くにいないので、実際にはこれを実際に試すことはできませんが、頭の上から、次のようなことができるはずです。
FocusManager.FocusedElement="{Binding ElementName=txtName}">
編集:
これについて(もっと最近尋ねられた)フォローアップの質問があります: xafocusでのみオートフォーカスを設定する方法? このメソッドと、その使用方法に関するいくつかの異なるアイデアが含まれています。
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から継承するすべてのコントロールで再利用できます。
これが誰かを助けることを願っています。
目的のコントロールでFocus()メソッドを呼び出すには、TriggerAction
が必要です。
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>
これはIan Oakesのソリューションと同じですが、いくつかの小さな変更を加えました。
ButtonBase
のように、より一般的なToggleButton
で、より多くのケースを処理できます。UIElement
にすることもできます。技術的には、これはIInputElement
になる可能性があります。イアンに感謝します。
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}}" />
イベントは元のボタン自体をターゲット/フォーカスできることに注意してください。
これは、あなたの望むことですか?
<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
}
Dispatcherを使用しているかどうかを確認してください。役立つでしょうが、これは私のコードで使用した短いトリックです。 XAMLでLoadedイベントを使用して、新しいハンドラーを作成するだけです。そのハンドラーにこのコードとビンゴを貼り付けてください!あなたは行く準備ができています
ここにいくつかの引数を持つ読み込まれたイベント...
{
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, new System.Action(() => {
The element to be focused goes here......
}));
}
PS:Windowsが必要です。あなたが知らなかった場合はスレッディング;)