示例程序:在TextBlock中,点击一个文字,其样式会改变,再一次点击后目标文字会还原原始样式。
诀窍就是使用TextBlock和RichTextBox类型的GetPositionFromPoint方法,point参数是在控件位置内的坐标,snapToText会自动根据位置来找到插入点(把他理解成类似光标的插入位置)。而当TextPointer返回后,TextPointer.LogicalDirection会指向鼠标的位置,这个是非常非常重要的。这样的话,用过这个返回的TextPointer,我们可以得到位置所指向的文字!
好,我们先设置好界面,XAML:
VerticalAlignment="Center"
Text="Mgen ABCDEFG HIGHLMN 一二三四五"
MouseLeftButtonUp="TextBlock_MouseLeftButtonUp"
FontSize="15"
Name="tbl"/>
我们可以在事件中(也就是TextBlock_MouseLeftButtonUp方法中)做一下测试:
var point = e.GetPosition(tbl);
//获取TextPointer
var poz = tbl.GetPositionFromPoint(point, true);
System.Diagnostics.Debug.WriteLine(poz.LogicalDirection);
如果点击一个文字的左侧,那么LogicalDirection是Forward,如果是右侧,LogicalDirection则会使Backward。
接下来就是获取文字和设置属性,使用TextPointer.GetNextInsertionPosition方法,参数则是获取的TextPointer.LogicalDirection属性,这样下一个TextPointer会指向文字的另一个方向。然后通过这两个TextPointer创建TextRange,通过GetPropertyValue和ApplyPropertyValue方法来获取TextRange的属性和设置属性,通过ClearAllProperties方法清空所有设置的属性,这样文字就又恢复原样了。
完成代码:
{
var point = e.GetPosition(tbl);
//获取TextPointer
var poz = tbl.GetPositionFromPoint(point, true);
var nextPoz = poz.GetNextInsertionPosition(poz.LogicalDirection);
if (nextPoz != null)
{
var range = new TextRange(poz, nextPoz);
//设置TextRange属性
var brush = range.GetPropertyValue(TextElement.ForegroundProperty);
if (brush.Equals(Brushes.YellowGreen))
{
range.ClearAllProperties();
}
else
{
range.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.YellowGreen);
range.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold);
range.ApplyPropertyValue(TextElement.FontSizeProperty, 30.0);
}
}
}
private void TextBlock_Loaded(object sender, RoutedEventArgs e)
{
try
{
List<TextRange> lstRange = FindAllMatchedTextRanges(sender as TextBlock, _FolderViewModel.FolderModel.SearchCOText);
foreach (var i in lstRange)
i.ApplyPropertyValue(TextBlock.ForegroundProperty, "#4682B4");
}
catch (PresentationException pex)
{
pex.Report();
}
catch (Exception ex)
{
new PresentationException(ex).Report();
}
}
private void TextBlock_Loaded_1(object sender, RoutedEventArgs e)
{
try
{
List<TextRange> lstRange = FindAllMatchedTextRanges(sender as TextBlock, _FolderViewModel.FolderModel.SearchCOText,true);
foreach (var i in lstRange)
i.ApplyPropertyValue(TextBlock.ForegroundProperty, "#4682B4");
}
catch (PresentationException pex)
{
pex.Report();
}
catch (Exception ex)
{
new PresentationException(ex).Report();
}
}
private List<TextRange> FindAllMatchedTextRanges(TextPointer position, string key)
{
List<TextRange> trList = new List<TextRange>();
while (position != null)
{
if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
{
String text = position.GetTextInRun(LogicalDirection.Forward);
Regex regex = new Regex(key, RegexOptions.IgnoreCase);
MatchCollection mc = regex.Matches(text);
foreach (Match match in mc)
{
TextPointer start = position.GetPositionAtOffset(match.Index);
TextPointer end = start.GetPositionAtOffset(match.Value.Length);
trList.Add(new TextRange(start, end));
}
}
position = position.GetNextContextPosition(LogicalDirection.Forward);
}
return trList;
}
private List<TextRange> FindAllMatchedTextRanges(TextBlock control, string keyWord)
{
List<TextRange> trList = new List<TextRange>();
List<TextRange> tLst = new List<TextRange>();
List<string> matchedAndKeys = new List<string>();
string[] orKeys,andKeys;
orKeys= keyWord.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string orkey in orKeys)
{
andKeys = orkey.Split(new string[] { "&&" }, StringSplitOptions.RemoveEmptyEntries);
matchedAndKeys.Clear();
tLst.Clear();
foreach (string andKey in andKeys)
{
var ttLst = FindAllMatchedTextRanges(control.ContentStart, andKey);
if (ttLst.Count > 0)
{
tLst.AddRange(ttLst);
matchedAndKeys.Add(andKey);
}
}
if (matchedAndKeys.Count == andKeys.Length)
trList.AddRange(tLst);
}
return trList;
}
private List<TextRange> FindAllMatchedTextRanges(TextBlock control, string keyWord, bool isTags)
{
string[] tags = control.Text.Split("|".ToArray(), StringSplitOptions.RemoveEmptyEntries);
control.Text = control.Text.Replace('|', ' ');
string[] orKeys, andKeys;
TextPointer position = control.ContentStart;
List<TextRange> tagTextRangeList = new List<TextRange>();
List<TextRange> trList = new List<TextRange>();
List<TextRange> tLst = new List<TextRange>();
List<string> matchedAndKeys = new List<string>();
orKeys = keyWord.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
while (position != null)
{
if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
{
String text = position.GetTextInRun(LogicalDirection.Forward);
foreach (string tag in tags)
{
Regex regex = new Regex(tag, RegexOptions.IgnoreCase);
Match match = regex.Match(text);
TextPointer start = position.GetPositionAtOffset(match.Index);
TextPointer end = start.GetPositionAtOffset(match.Value.Length);
tagTextRangeList.Add(new TextRange(start, end));
}
foreach (string orkey in orKeys)
{
andKeys = orkey.Split(new string[] { "&&" }, StringSplitOptions.RemoveEmptyEntries);
matchedAndKeys.Clear();
tLst.Clear();
foreach (TextRange tag in tagTextRangeList)
{
foreach (string andKey in andKeys)
{
var ttLst = FindAllMatchedTextRanges(tag.Start, andKey);
if (ttLst.Count > 0)
{
tLst.AddRange(ttLst);
matchedAndKeys.Add(andKey);
}
}
if (matchedAndKeys.Count == andKeys.Length)
trList.AddRange(tLst);
}
}
}
position = position.GetNextContextPosition(LogicalDirection.Forward);
}
return trList;
}