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

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

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

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

textbox

HTMLの<input type="text">で生成されるtextboxに関するタグです。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

2回答

2744閲覧

TextBoxに入力されたテキストを判定し、RichTextBoxのテキストの色を順次変えていきたい

MineMine

総合スコア1

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

textbox

HTMLの<input type="text">で生成されるtextboxに関するタグです。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

1グッド

0クリップ

投稿2021/09/29 11:14

### (C#,WPF)RichTextBoxで入力された文字があっていれば文字の色を変化させる

初めての質問で至らない点があれば申し訳ありません。
WPFでタイピングゲームを開発したいと思い、寿司打のデザインを参考にして開発をしています。表示されているローマ字を入力し、テキストが合っていれば入力したテキスト分のローマ字が赤色に変化するようにしたいです。

色は変化していくが2文字目から変化する色にズレが生じる

最初の文字は赤色に変化しますが、2文字目、3文字目を入力しても色が変化せず、4文字目でまた色が赤色に変わり始めます。
文を打ち終わるころには最初の2文字分赤色に変化していない部分が存在してしまいます。
下記のコードにこだわりがあるわけではない為、寿司打を再現できる簡単な方法があればよいのですが…

該当のソースコード

C#

1String ans; 2String kaitou = "tonarinokyakuhayokukakikuukyakuda"; 3TextPointer p; 4ans = tb.Text; 5 6 if(ans.Substring(ans.Length-1,1) == kaitou.Substring(ans.Length - 1, 1)) 7 { 8 p = rtb.CaretPosition.GetPositionAtOffset(ans.Length); 9 TextRange textRange = new TextRange(rtb.Document.ContentStart, p); 10 textRange.ApplyPropertyValue(TextElement.ForegroundProperty,Brushes.Red); 11 }

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

.NET FrameWork 4.7.2
Visual Studio 2019で開発しています。

TN8001👍を押しています

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

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

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

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

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

dodox86

2021/09/29 11:51

あまりにコードが断片的で、第三者には再現できない、問題点を特定できないかもしれません。1文字目はOK,2、3文字目はNG,4文字目からまたOK、ということは、何かしらキー入力やコントロールの入力内容の変更イベント発生のところなどで実行しているコードなのでしょうか。 可能な限り第三者に再現できるコードにして、更には人間が入力したパターンも載せた方が良いと思います。
MineMine

2021/10/01 09:11

投稿ありがとうございます! 次の質問をする際には、第三者からの視点を考えて質問をしようと思います…
dodox86

2021/10/01 09:47

回答を2つもいただけていたので、ご質問の意図は分かる方には分かる分野のものかとも思いました。(私にはいまだに分かりませんでしたが、、、)題材としては面白そうなものなので、がんばってぜひ完成させてください。
guest

回答2

0

「下記のコードにこだわりがあるわけではない」という事を曲解して、RichTextBoxというのを完全に無視した回答です。
※RichTextBoxを使うのが難しいなら画像でやったら良いじゃない。という例

XAML

1<Window x:Class="Q361934.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:Q361934" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="450" Width="800" SizeChanged="Window_SizeChanged" KeyDown="Window_KeyDown"> 9 <Grid> 10 <Canvas x:Name="canvas1" Width="Auto" Height="Auto"> 11 <Image Source="{Binding Background}" Panel.ZIndex="0"/> 12 <Image Source="{Binding Foreground}" Panel.ZIndex="1" Canvas.Left="{Binding Left}" Canvas.Top="{Binding Top}"/> 13 </Canvas> 14 </Grid> 15</Window>

C#

1using System; 2using System.ComponentModel; 3using System.Globalization; 4using System.Windows; 5using System.Windows.Input; 6using System.Windows.Media; 7using System.Windows.Media.Imaging; 8 9namespace Q361934 { 10 /// <summary> 11 /// Interaction logic for MainWindow.xaml 12 /// </summary> 13 public partial class MainWindow : Window { 14 ViewModel vm; 15 public MainWindow() { 16 InitializeComponent(); 17 vm = new ViewModel(); 18 vm.CanvasSize = canvas1.RenderSize; 19 this.DataContext = vm; 20 } 21 22 private void Window_SizeChanged(object sender, SizeChangedEventArgs e) { 23 vm.CanvasSize = canvas1.RenderSize; 24 } 25 26 private void Window_KeyDown(object sender, KeyEventArgs e) { 27 if (e.Key >= Key.A && e.Key <= Key.Z) { 28 if (vm.Kaitou.Length == vm.InputText.Length) return; 29 var k = vm.Kaitou.Substring(vm.InputText.Length, 1); 30 if (string.Compare(k, e.Key.ToString(), StringComparison.CurrentCultureIgnoreCase) == 0) 31 vm.InputText += k; 32 } 33 } 34 } 35 public class ViewModel : INotifyPropertyChanged { 36 public event PropertyChangedEventHandler PropertyChanged; 37 private void OnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); 38 39 private int FGWidth = 400; 40 private int FGHeight = 30; 41 42 public string Kaitou { get; set; } = "tonarinokyakuhayokukakikuukyakuda"; 43 44 Size _CanvasSize = new Size(0, 0); 45 public Size CanvasSize { 46 get { return _CanvasSize; } 47 set { 48 _CanvasSize = value; 49 OnPropertyChanged(nameof(CanvasSize)); 50 OnPropertyChanged(nameof(Left)); 51 OnPropertyChanged(nameof(Top)); 52 OnPropertyChanged(nameof(Background)); 53 OnPropertyChanged(nameof(Foreground)); 54 } 55 } 56 public int Left { 57 get { return (int)((CanvasSize.Width - FGWidth) / 2); } 58 } 59 public int Top { 60 get { return (int)((CanvasSize.Height - FGHeight) / 2); } 61 } 62 63 string _InputText = ""; 64 public string InputText { 65 get { return _InputText; } 66 set { 67 _InputText = value; 68 OnPropertyChanged(nameof(InputText)); 69 OnPropertyChanged(nameof(Foreground)); 70 } 71 } 72 73 public BitmapSource Background { 74 get { 75 var text = ""; 76 for (int i = 0; i < 200; i++) text += "Background "; 77 var visual = new DrawingVisual(); 78 using (DrawingContext drawingContext = visual.RenderOpen()) { 79 drawingContext.DrawRectangle( 80 Brushes.Black, 81 new Pen(Brushes.Black, 100.0), 82 new Rect(0, 0, CanvasSize.Width, CanvasSize.Height)); 83 var ft = new FormattedText(text, 84 CultureInfo.CurrentCulture, 85 FlowDirection.LeftToRight, 86 new Typeface(SystemFonts.MessageFontFamily.Source), 87 24.0, 88 Brushes.White, 89 1.0); 90 ft.MaxTextWidth = CanvasSize.Width - 20; 91 drawingContext.DrawText(ft, new Point(10.0, 10.0)); 92 } 93 var rtb = new RenderTargetBitmap((int)CanvasSize.Width, (int)CanvasSize.Height, 96, 96, PixelFormats.Pbgra32); 94 rtb.Render(visual); 95 return rtb; 96 } 97 } 98 public BitmapSource Foreground { 99 get { 100 var visual = new DrawingVisual(); 101 using (DrawingContext drawingContext = visual.RenderOpen()) { 102 drawingContext.DrawRectangle( 103 Brushes.Black, 104 new Pen(Brushes.Gray, 100.0), 105 new Rect(0, 0, FGWidth, FGHeight)); 106 var ft = new FormattedText(Kaitou, 107 CultureInfo.CurrentCulture, 108 FlowDirection.LeftToRight, 109 new Typeface(SystemFonts.MessageFontFamily.Source), 110 16.0, 111 Brushes.White, 112 1.0); 113 ft.MaxTextWidth = FGWidth - 20; 114 drawingContext.DrawText(ft, new Point(10.0, 0.0)); 115 116 ft = new FormattedText(InputText, 117 CultureInfo.CurrentCulture, 118 FlowDirection.LeftToRight, 119 new Typeface(SystemFonts.MessageFontFamily.Source), 120 16.0, 121 Brushes.Red, 122 1.0); 123 ft.MaxTextWidth = FGWidth - 20; 124 drawingContext.DrawText(ft, new Point(10.0, 0.0)); 125 } 126 var rtb = new RenderTargetBitmap(FGWidth, FGHeight, 96, 96, PixelFormats.Pbgra32); 127 rtb.Render(visual); 128 return rtb; 129 } 130 } 131 } 132}

投稿2021/09/30 09:51

Hey_CH

総合スコア437

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

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

TN8001

2021/09/30 10:10

力作ですね^^ その発想はなかったです(かえって難し…ゲフンゲフン笑
Hey_CH

2021/09/30 11:03

ちょうど最近WPFでBitmapSourceを描画して返す処理を作ったので、なんとなくやってみましたw
MineMine

2021/10/01 08:37

Hey_CHさんありがとうございます! 今回はTN8001さんの回答を使わせて頂きますが、別の機会にHey_CHさんのコードを使用させていただくかも知れません!投稿ありがとうございます!
Hey_CH

2021/10/01 11:01

了解です~頑張ってください!
guest

0

ベストアンサー

ぶっちゃけなにもわかってません^^;

TextPointer.GetPositionAtOffset メソッド (System.Windows.Documents) | Microsoft Docs
は「シンボル単位」となっており、「文字単位」ではないようです。
そのためTextPointerを、うまく送れてないのではないでしょうか?

適当にggって見つけたコードで置き換えたところ、それっぽく動いている気はします。
c# - Select Range of Text in WPF RichTextBox (FlowDocument) Programmatically - Stack Overflow

xml

1<Window 2 x:Class="Questions361934.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 Width="800" 6 Height="450"> 7 <Grid> 8 <Grid.RowDefinitions> 9 <RowDefinition /> 10 <RowDefinition /> 11 <RowDefinition /> 12 </Grid.RowDefinitions> 13 <RichTextBox x:Name="rtb"> 14 <FlowDocument> 15 <Paragraph> 16 tonarinokyakuhayokukakikuukyakuda 17 </Paragraph> 18 </FlowDocument> 19 </RichTextBox> 20 21 <TextBlock Grid.Row="1" Text="tonarinokyakuhayokukakikuukyakuda" /> 22 <TextBlock 23 x:Name="textBlock" 24 Grid.Row="1" 25 Foreground="Red" /> 26 27 <TextBox 28 x:Name="tb" 29 Grid.Row="2" 30 TextChanged="TextChanged" /> 31 </Grid> 32</Window>

cs

1using System.Windows; 2using System.Windows.Controls; 3using System.Windows.Documents; 4using System.Windows.Media; 5 6namespace Questions361934 7{ 8 public partial class MainWindow : Window 9 { 10 public MainWindow() => InitializeComponent(); 11 12 private void TextChanged(object sender, TextChangedEventArgs e) 13 { 14 var textRange = new TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd); 15 textRange.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Black); 16 17 textBlock.Text = ""; 18 19 var kaitou = "tonarinokyakuhayokukakikuukyakuda"; 20 var ans = tb.Text; 21 if (kaitou.StartsWith(ans)) 22 { 23 var p = GetPoint(rtb.Document.ContentStart, ans.Length); 24 textRange = new TextRange(rtb.Document.ContentStart, p); 25 textRange.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Red); 26 27 textBlock.Text = ans; 28 } 29 } 30 31 // [c# - Select Range of Text in WPF RichTextBox (FlowDocument) Programmatically - Stack Overflow](https://stackoverflow.com/questions/1454440/select-range-of-text-in-wpf-richtextbox-flowdocument-programmatically/12399115#12399115) 32 private static TextPointer GetPoint(TextPointer start, int x) 33 { 34 var ret = start; 35 var i = 0; 36 while (ret != null) 37 { 38 var stringSoFar = new TextRange(ret, ret.GetPositionAtOffset(i, LogicalDirection.Forward)).Text; 39 if (stringSoFar.Length == x) break; 40 41 i++; 42 if (ret.GetPositionAtOffset(i, LogicalDirection.Forward) == null) 43 return ret.GetPositionAtOffset(i - 1, LogicalDirection.Forward); 44 } 45 return ret.GetPositionAtOffset(i, LogicalDirection.Forward); 46 } 47 } 48}

下記のコードにこだわりがあるわけではない為、寿司打を再現できる簡単な方法があればよいのですが…

雑にやるならTextBlockを重ねるとか?(ちょっと文字が太ってみえる)

アプリ動画

投稿2021/09/29 15:01

編集2023/07/29 06:18
TN8001

総合スコア9319

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

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

TN8001

2021/09/29 20:53

色をいったん黒に戻す処理を後で入れたのですが(挙動が気に入らなかったので^^; それを入れた状態なら質問コードのままでいけますね。。。(CaretPositionを動かさなければ) * ContentStartの後にFlowDocumentやParagraphがいる * 色を変えた境目にも「何か」がいる のでGetPositionAtOffsetがずれる(文字以外の「何か」も計算に入れなくてはならない) 黒に戻した場合は境目の「何か」が消えて、文字数分で済んでしまうということのようですね。 とはいえ「何か」を気にするのも面倒ですしCaretPositionに依存するのも気持ちが悪いので、GetPointの意味はあるのではないかと思います。
MineMine

2021/10/01 08:42

なるほど…GetPointを使えばよかったのですね! RichTextBoxは初心者の私にとって扱いが難しいです笑 私が3日間止まっていた部分がこんなに簡単に解決してしまうのは少し悔しさを感じてしまいます笑 どうもありがとうございました!
MineMine

2021/10/01 08:46 編集

ベストアンサーとさせて頂きます!!
TN8001

2021/10/01 09:41

> なるほどGetPointAtOffsetではなくGetPointを使用すればよいのですね… MineMineさんは分かっておられるのでしょうが、これだけ読むとGetPointというメソッドが用意されているかのように読めてしまいます。 文字以外の要素を読み飛ばす、GetPointメソッドを自分で作るということですね。 > RichTextBoxは初心者の私にとって扱いが難しいです笑 いえ私もさっぱりわかりませんwむずかしすぎますね。 わたしも過去にタイピングソフト作成のお手伝いをしたことがあります(本体のコードは書いていません。一緒に考えたり、問題文を作ったり等) いいのができるといいですね^^がんばってください。
MineMine

2021/10/02 12:06

ありがとうございます!頑張ります!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問