web-dev-qa-db-ja.com

WPF-ボタンがクリックされたときにフォーカスを設定-背後にコードがない

WPF Focussを使用して、あるコントロールから別のコントロールに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パターンにどのように適合するかについて、ある種のドキュメントが欲しいです。

25
Vaccano

添付された動作の使用を検討しましたか? 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" />
32
Ian Oakes

私はビジュアルスタジオの近くにいないので、実際にはこれを実際に試すことはできませんが、頭の上から、次のようなことができるはずです。

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

編集:

これについて(もっと最近尋ねられた)フォローアップの質問があります: xafocusでのみオートフォーカスを設定する方法? このメソッドと、その使用方法に関するいくつかの異なるアイデアが含まれています。

16
caesay

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から継承するすべてのコントロールで再利用できます。

これが誰かを助けることを願っています。

10
droidalmatter

目的のコントロールで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>
4
ar.gorgin

これは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}}" />

イベントは元のボタン自体をターゲット/フォーカスできることに注意してください。

1
Glenn Slayden

これは、あなたの望むことですか?

    <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
    }
1
mg007

Dispatcherを使用しているかどうかを確認してください。役立つでしょうが、これは私のコードで使用した短いトリックです。 XAMLでLoadedイベントを使用して、新しいハンドラーを作成するだけです。そのハンドラーにこのコードとビンゴを貼り付けてください!あなたは行く準備ができています

ここにいくつかの引数を持つ読み込まれたイベント...

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

PS:Windowsが必要です。あなたが知らなかった場合はスレッディング;)

0
Yash Joshi