FlowDocumentでユーザーがクリックしたという言葉を取得したいと思います。
私は現在、すべてにイベントハンドラを追加していますドキュメント内で実行し、クリックされたRun内のTextPointersを反復処理し、それぞれに対してGetCharacterRect()を呼び出し、四角形にポイントが含まれているかどうかを確認します。
ただし、長い実行の終わり近くにクリックが発生すると、10秒以上かかります。
より効率的な方法はありますか?
回答:
回答№1は6最も簡単な方法は、オートメーションインターフェイスを使用することです。
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
FlowDocument flowDocument = ...;
Point point = ...;
var peer = new DocumentAutomationPeer(flowDocument);
var textProvider = (ITextProvider)peer.GetPattern(PatternInterface.Text);
var rangeProvider = textProvider.RangeFromPoint(point);
ITextProviderの使用には、への参照が必要ですUIAutomationProviderアセンブリ。このアセンブリは一般的に参照されないため、追加する必要があります。 UIAutomationTypesは、そのメソッドの一部を使用するためにも必要です。
FlowDocumentの表示方法に応じて、オートメーションピアを作成するための多くのオプションがあることに注意してください。
var peer = new DocumentAutomationPeer(flowDocument);
var peer = new DocumentAutomationPeer(textBlock);
var peer = new DocumentAutomationPeer(flowDocumentScrollViewer);
var peer = new TextBoxAutomationPeer(textBox);
var peer = new RichTextBoxAutomationPeer(richTextBox);
更新
ITextRangeProviderからTextPointerへの変換は予想以上に困難でしたが、私はこれを試しましたが、うまく機能しました。
拡張メソッドにアルゴリズムをパッケージ化しました ScreenPointToTextPointer
簡単に使用できます。以下に、拡張メソッドを使用して、マウスポインターの前のすべてのテキストを太字にし、その後のすべてのテキストの太字を解除する方法の例を示します。
private void Window_MouseMove(object sender, MouseEventArgs e)
{
var document = this.Viewer.Document;
var screenPoint = PointToScreen(e.GetPosition(this));
TextPointer pointer = document.ScreenPointToTextPointer(screenPoint);
new TextRange(document.ContentStart, pointer).ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold);
new TextRange(pointer, document.ContentEnd).ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Normal);
}
拡張メソッドのコードは次のとおりです。
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using System.Windows.Automation.Text;
public static class DocumentExtensions
{
// Point is specified relative to the given visual
public static TextPointer ScreenPointToTextPointer(this FlowDocument document, Point screenPoint)
{
// Get text before point using automation
var peer = new DocumentAutomationPeer(document);
var textProvider = (ITextProvider)peer.GetPattern(PatternInterface.Text);
var rangeProvider = textProvider.RangeFromPoint(screenPoint);
rangeProvider.MoveEndpointByUnit(TextPatternRangeEndpoint.Start, TextUnit.Document, 1);
int charsBeforePoint = rangeProvider.GetText(int.MaxValue).Length;
// Find the pointer that corresponds to the TextPointer
var pointer = document.ContentStart.GetPositionAtOffset(charsBeforePoint);
// Adjust for difference between "text offset" and actual number of characters before pointer
for(int i=0; i<10; i++) // Limit to 10 adjustments
{
int error = charsBeforePoint - new TextRange(document.ContentStart, pointer).Text.Length;
if(error==0) break;
pointer = pointer.GetPositionAtOffset(error);
}
return pointer;
}
}
また、サンプルのMouseMoveメソッドでPointToScreenを使用して、スクリーンポイントを取得して拡張メソッドに渡すことにも注意してください。
回答№2の場合は1
FlowDocumentがRichTextBoxのものである場合、使用できます GetPositionFromPoint() TextPointerを取得するメソッド。
回答№3の場合は0
マウスクリックイベントは上部にバブル表示され、代わりに、単にPreviewMouseLeftButtonUpをドキュメントにフックして、イベントの送信者/元のソースを監視するだけで、イベントを送信したRunを取得できます。
次に、RangeFromPointを使用して、使用できます。
ローカルマウスポイントをグローバルポイントに変換するPointToScreen。