### (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で開発しています。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/10/01 09:11
2021/10/01 09:47
回答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
総合スコア437
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
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総合スコア9807
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/09/29 20:53
2021/10/01 08:42
2021/10/01 08:46 編集
2021/10/01 09:41
2021/10/02 12:06
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。