質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%

Q&A

解決済

1回答

1379閲覧

WPFのMVVMフレームワークでディスプレイキーボードを実装する際に、SendWaitがうまく機能しない件について

ky6140

総合スコア1

1グッド

0クリップ

投稿2023/03/14 12:35

編集2023/03/16 21:44

実現したいこと

WPFのMVVMフレームワークでディスプレイキーボードを実装する。

前提

WPFのMVVMでディスプレイキーボード作成を試みていますが、SendWaitを使用するとなぜかUIのTextBox側ではなく、コードに内容が反映されます。また、なぜかBackSpaceはちゃんとTextBoxに反映されます。何がいけないのでしょうか?

発生している問題・エラーメッセージ

特になし(SendWaitが反映されない)

該当のソースコード

c#

1// MainViewModelです。 2using System.Windows.Forms; 3 4namespace SendWaitTest 5{ 6 public sealed class MainViewModel:ViewModelBase 7 { 8 public MainViewModel() 9 { 10 ACommand = new DelegateCommand<string>(x=> ACommandExecute(x)); 11 BsCommand = new DelegateCommand<string>(x => BsCommandExecute(x)); 12 } 13 14 public DelegateCommand<string> ACommand { get; } 15 16 public DelegateCommand<string> BsCommand { get; } 17 18 private bool isFocus; 19 public bool IsFocus 20 { 21 get=> isFocus; 22 set=>SetProperty(ref isFocus, value); 23 } 24 25 private string dataName; 26 public string DataName 27 { 28 get => dataName; 29 set => SetProperty(ref dataName, value); 30 } 31 32 private void ACommandExecute(string x) 33 { 34 IsFocus = true; 35 SendKeys.SendWait("A"); 36 IsFocus = false; 37 } 38 39 private void BsCommandExecute(string x) 40 { 41 IsFocus = true; 42 SendKeys.SendWait("{BS}"); 43 IsFocus=false; 44 } 45 } 46}

C#

1// View側です。(XAMLコードです。) 2<Window x:Class="SendWaitTest.MainView" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 7 xmlns:local="clr-namespace:SendWaitTest" 8 mc:Ignorable="d" 9 Title="MainView" Height="300" Width="300"> 10 <Grid> 11 <Grid.RowDefinitions> 12 <RowDefinition Height="1*"/> 13 <RowDefinition Height="1*"/> 14 <RowDefinition Height="1*"/> 15 </Grid.RowDefinitions> 16 17 <TextBox Name="Text" Margin="10" Width="250" FontSize="14" Grid.Row="0" HorizontalAlignment="Center" Text="{Binding DataName}"> 18 <TextBox.Style> 19 <Style TargetType="TextBox"> 20 <Style.Triggers> 21 <DataTrigger Binding="{Binding IsFocus}" Value="True"> 22 <Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName= Text}"></Setter> 23 </DataTrigger> 24 </Style.Triggers> 25 </Style> 26 </TextBox.Style> 27 </TextBox> 28 29 <Button FontSize="14" Margin="10" Grid.Row="1" Content="A" Command="{Binding ACommand}"></Button> 30 <Button FontSize="14" Margin="10" Grid.Row="2" Content="BackSpace" Command="{Binding BsCommand}"></Button> 31 </Grid> 32</Window>

C#

1// ViewModelBaseです。 2using System.ComponentModel; 3using System.Runtime.CompilerServices; 4 5namespace SendWaitTest 6{ 7 public abstract class ViewModelBase : INotifyPropertyChanged 8 { 9 public event PropertyChangedEventHandler PropertyChanged; 10 11 protected bool SetProperty<T>(ref T field, 12 T value, [CallerMemberName] string propertyName = null) 13 { 14 if (Equals(field, value)) 15 { 16 return false; 17 } 18 19 field = value; 20 var h = this.PropertyChanged; 21 if (h != null) 22 { 23 h(this, new PropertyChangedEventArgs(propertyName)); 24 } 25 26 return true; 27 } 28 } 29}

C#

1//DelegateCommandクラスです。 2using System; 3using System.Windows.Input; 4 5namespace SendWaitTest 6{ 7 public sealed class DelegateCommand<T>:ICommand 8 { 9 public event EventHandler CanExecuteChanged; 10 private readonly Action<T> action; 11 private readonly Func<T,bool> canExcute; 12 13 public DelegateCommand(Action<T> action, Func<T, bool> canExcute = default) 14 { 15 this.action = action; 16 this.canExcute = canExcute; 17 } 18 19 public bool CanExecute(object parameter) 20 { 21 return canExcute?.Invoke((T)parameter) ?? true; 22 } 23 24 public void Execute(object parameter) 25 { 26 action?.Invoke((T)parameter); 27 } 28 29 public void DelegateCanExcute() 30 { 31 CanExecuteChanged?.Invoke(this, EventArgs.Empty); 32 } 33 } 34}

試したこと

補足情報(FW/ツールのバージョンなど)

VisualStudio2022を使用しており、C#のバージョンは7.3です。MVVMのフレームワークは使用していません。

※Teratailの規約をよく理解しておらず、別サイトでも質問してしまっています。
※念のため掲載しておきます。(2023/3/17)
MVVMでWPFを用いてSendWaitを画面に反映する方法

TN8001👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TN8001

2023/03/14 14:20

コードがとても見にくいので、それぞれをコードブロックにしてください。 [ヘルプ | 質問する時のヒント](https://teratail.com/help/question-tips#questionTips35) > SendWaitを使用するとなぜかUIのTextBox側ではなく、コードに内容が反映されます。また、なぜかBackSpaceはちゃんとTextBoxに反映されます。 なんか不思議ですね。 SendWaitできるものはほんの一部で、大体はできないですね... > WPFのMVVMフレームワークで 「MVVM」が重要なポイントでしょうか?(↓みたいのは避けたい) private void Button_Click(object sender, RoutedEventArgs e) { Text.SelectedText = "A"; Text.CaretIndex = Text.SelectionStart + "A".Length; } > ディスプレイキーボードを実装する。 これはあくまでテストであって、本来は「ほかのアプリ」に送信するつもりでしょうか?(いわゆる「ソフトウェアキーボード」・「スクリーンキーボード」といった種類のアプリ)
ky6140

2023/03/14 22:08

ありがとうございます、コードはブロックにしました。初心者なもので、不慣れで申し訳ありません。 >SendWaitできるものはほんの一部で、大体はできないですね... そうなんですね、、WPFだとSendKeyも使用できないですし、結構制約されますね… >「MVVM」が重要なポイントでしょうか? 本業の方でWinFormをWPFに置き換えるという計画が走ってまして、基本的なコードは全てMVVMで行うとの方針ですので、コードビハインドは使用したくはないです。 >これはあくまでテストであって、本来は「ほかのアプリ」に送信するつもりでしょうか? おっしゃる通りで、これは質問用のコードで実際は他のアプリに送信することにも使用しようと思っていました。
TN8001

2023/03/15 03:58

[MVVMでWPFを用いてSendWaitを画面に反映する方法](http://bbs.wankuma.com/index.cgi?mode=al2&namber=101553) > teratailでは、マルチポスト※の推奨はしていません。 > やむを得ず複数のサイトに質問を投稿された場合は、質問内容にマルチポストをする理由を書き、他のサイトの投稿へのリンクを貼ってください。 また、解決した際には必ずteratail及びすべての投稿に解決した旨と、どのように解決したかを記載してください。 [ヘルプ|他のサービスにも質問投稿をしたい(してしまった)](https://teratail.com/help#posted-otherservice)
ky6140

2023/03/15 22:06

> teratailでは、マルチポスト※の推奨はしていません。 そうだったのですね、追加で情報ありがとうございます。そのように処理するようにします。
guest

回答1

0

ベストアンサー

とりあえずこんなのでテストしてみました。

cs

1private async void Button_Click(object sender, RoutedEventArgs e) 2{ 3 await Task.Delay(TimeSpan.FromSeconds(5)); 4 SendKeys.SendWait("A"); 5}

5秒の間にメモ帳等をアクティブにすると、(まあ当然ながら)Aが入力されました。
しかし自分のTextBoxにキーボードフォーカスがあっても、Aは入力されませんでした(BSはいけた)
同じアプリを(「デバッグなしで実行」等で)複数立ち上ると、お互いにはAも入力されました。

半ばやけになってこのように変更したところ、なぜかAも入力されるようになりました(訳が分からない^^;

cs

1private void Button_Click(object sender, RoutedEventArgs e) 2{ 3 Task.Run(async () => 4 { 5 await Task.Delay(TimeSpan.FromSeconds(5)); 6 SendKeys.SendWait("A"); 7 }); 8}

それを踏まえて微調整したところ、こちらの手元ではいい感じに動いています(デバッグありだとリピートが引っかかる。なしならスムーズ)

xml

1<Window 2 x:Class="Q0pelmw9lnpqil6.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:local="clr-namespace:Q0pelmw9lnpqil6" 6 Width="300" 7 Height="400" 8 FontSize="14"> 9 <Window.DataContext> 10 <local:MainViewModel /> 11 </Window.DataContext> 12 <UniformGrid Columns="1"> 13 <TextBox Margin="10" Text="{Binding DataName}"> 14 <TextBox.Style> 15 <Style TargetType="TextBox"> 16 <Style.Triggers> 17 <DataTrigger Binding="{Binding IsFocus}" Value="True"> 18 <Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}" /> 19 </DataTrigger> 20 </Style.Triggers> 21 </Style> 22 </TextBox.Style> 23 </TextBox> 24 25 <!-- RepeatButtonにしたら2回目以降が来なくなり、Focusable="False"が必要なよう --> 26 <RepeatButton 27 Margin="10" 28 Command="{Binding Command}" 29 CommandParameter="A" 30 Content="A" 31 Focusable="False" /> 32 <RepeatButton 33 Margin="10" 34 Command="{Binding Command}" 35 CommandParameter="{}{BS}" 36 Content="BackSpace" 37 Focusable="False" /> 38 39 <Button 40 Margin="10" 41 Click="Button_Click" 42 Content="A after 5s" /> 43 </UniformGrid> 44</Window>

cs

1using System; 2using System.ComponentModel; 3using System.Runtime.CompilerServices; 4using System.Threading.Tasks; 5using System.Windows; 6using System.Windows.Forms; 7using System.Windows.Input; 8 9namespace Q0pelmw9lnpqil6 10{ 11 public sealed class MainViewModel : ViewModelBase 12 { 13 public bool IsFocus { get => isFocus; set => SetProperty(ref isFocus, value); } 14 private bool isFocus; 15 16 public string DataName { get => dataName; set => SetProperty(ref dataName, value); } 17 private string dataName = "aaaa"; 18 19 public DelegateCommand<string> Command { get; } 20 21 public MainViewModel() => Command = new DelegateCommand<string>(CommandExecute); 22 23 private void CommandExecute(string x) 24 { 25 IsFocus = true; 26 Task.Run(() => 27 { 28 // ここだとなんか安定しなかった 29 //IsFocus = true; 30 SendKeys.SendWait(x); 31 IsFocus = false; 32 }); 33 } 34 } 35 36 public partial class MainWindow : Window 37 { 38 public MainWindow() => InitializeComponent(); 39 40 //private async void Button_Click(object sender, RoutedEventArgs e) 41 //{ 42 // await Task.Delay(TimeSpan.FromSeconds(5)); 43 // SendKeys.SendWait("A"); 44 // //SendKeys.SendWait("{BS}"); 45 //} 46 47 private void Button_Click(object sender, RoutedEventArgs e) 48 { 49 // バカっぽいけどButton_Clickを抜けることが重要?? 50 Task.Run(async () => 51 { 52 await Task.Delay(TimeSpan.FromSeconds(5)); 53 SendKeys.SendWait("A"); 54 //SendKeys.SendWait("{BS}"); 55 }); 56 } 57 } 58 59 60 public abstract class ViewModelBase : INotifyPropertyChanged 61 { 62 public event PropertyChangedEventHandler PropertyChanged; 63 protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null) 64 { 65 if (Equals(field, value)) return false; 66 field = value; 67 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 68 return true; 69 } 70 } 71 public sealed class DelegateCommand<T> : ICommand 72 { 73 public event EventHandler CanExecuteChanged; 74 private readonly Action<T> action; 75 private readonly Func<T, bool> canExcute; 76 public DelegateCommand(Action<T> action, Func<T, bool> canExcute = default) => (this.action, this.canExcute) = (action, canExcute); 77 public bool CanExecute(object parameter) => canExcute?.Invoke((T)parameter) ?? true; 78 public void Execute(object parameter) => action?.Invoke((T)parameter); 79 public void DelegateCanExcute() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); 80 } 81}

投稿2023/03/15 04:00

TN8001

総合スコア9819

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TN8001

2023/03/15 04:00

> おっしゃる通りで、これは質問用のコードで実際は他のアプリに送信することにも使用しようと思っていました。 わたしもWPFでソフトウェアキーボードを自作して常用しています^^
ky6140

2023/03/15 22:16

お世話になっております。本件、ご回答ありがとうございます。 なるほど、クリックイベントからから抜けて別スレッドなら動作できるということですね…! 申し訳ございませんが今繁忙期ですので、週末に私の方で試してみた後にベストアンサーにさせてください。
TN8001

2023/03/16 03:46

こちらは急いでいませんのでゆっくりどうぞ^^
ky6140

2023/03/16 21:46

色々ありがとうございます。 本日自環境でも試しましたが、問題なく動作することを確認いたしました。 WPFは周りに詳しい方がおらず困っていたので非常に助かりました!また頼らせて頂くかもしれませんが、その時は宜しくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問