告诉我为什么我的控件变慢了,尽管它是从并行线程调用的。
我正在尝试为.NET 4.0 ( HighlightTextBlock )创建一个控件,它将以黄色突出显示子文本。这个想法是,如果找到子文本,则ContentControl的Content变成3 Runs的TextBlock ,其中一个以黄色突出显示。
result.Add(new Run(stringBefore));result.Add(new Run(stringMatch) { Background = this.HighlightBrush });result.Add(new Run(stringAfter));
如果未找到子文本,则仅插入文本。
一切都已经证明并有效,但问题在于性能。
我将更详细地描述:
此控件用于可能有数百条记录的工作表中。子文本在TextBox中编辑。绑定到这个文本框如下:HighlightText = "{Binding ElementName=myTextBox, Path=Text}"。如果您编辑此子文本,它会冻结,光标会“跳动”,如图所示。对于每次击键,都会执行代码以突出显示文本,并且很明显它在我的控制下已经减慢了 30 行。
在我的控制范围内,我试图这样做:
Dispatcher.BeginInvoke(
(ThreadStart)delegate
{
//update control
}
);
因此,通过异步:
Task.Factory.StartNew(/*поиск в строке и разбиение строки на 3 части*/)
.ContinueWith(
x =>
{
//update control
}
,TaskScheduler.FromCurrentSynchronizationContext()
);
但是不可能摆脱刹车。
您可以检查一个简单示例的控件(我立即手写)。制动已经发生在 30 行。
<TextBox Name="myTextBox"/>
<ItemsControl>
<ItemsControl.Items>
<!-- ... -->
<controls:HighlightTextBlock Text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" HighlightText = "{Binding ElementName=myTextBox, Path=Text}"/>
<controls:HighlightTextBlock Text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" HighlightText = "{Binding ElementName=myTextBox, Path=Text}"/>
<controls:HighlightTextBlock Text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" HighlightText = "{Binding ElementName=myTextBox, Path=Text}"/>
<controls:HighlightTextBlock Text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" HighlightText = "{Binding ElementName=myTextBox, Path=Text}"/>
<controls:HighlightTextBlock Text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" HighlightText = "{Binding ElementName=myTextBox, Path=Text}"/>
<controls:HighlightTextBlock Text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" HighlightText = "{Binding ElementName=myTextBox, Path=Text}"/>
<controls:HighlightTextBlock Text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" HighlightText = "{Binding ElementName=myTextBox, Path=Text}"/>
<!-- ... -->
</ItemsControl.Items>
</ItemsControl>
这是承诺的完全控制代码。无论有没有调试器,它都会变慢。
public class HighlightTextBlock : ContentControl
{
public string Text
{
get { return (string)GetValue(TextProperty); }
set
{
SetValue(TextProperty, value);
}
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(HighlightTextBlock), new UIPropertyMetadata("", new PropertyChangedCallback(TextProperty_PropertyChanged)));
private static void TextProperty_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as HighlightTextBlock;
control.SetContent();
}
public string HighlightText
{
get { return (string)GetValue(HighlightTextProperty); }
set
{
SetValue(HighlightTextProperty, value);
}
}
public static readonly DependencyProperty HighlightTextProperty =
DependencyProperty.Register("HighlightText", typeof(string), typeof(HighlightTextBlock), new UIPropertyMetadata("", new PropertyChangedCallback(HighlightTextProperty_PropertyChanged)));
private static void HighlightTextProperty_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as HighlightTextBlock;
control.SetContent();
}
public Brush HighlightBrush
{
get { return (Brush)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
public static readonly DependencyProperty ColorProperty =
DependencyProperty.Register("HighlightBrush",
typeof(Brush),
typeof(HighlightTextBlock),
new UIPropertyMetadata(Brushes.Orange));
static HighlightTextBlock()
{
//DefaultStyleKeyProperty.OverrideMetadata(typeof(ContentControl), new FrameworkPropertyMetadata(typeof(ContentControl)));
}
private TextBlock TextContent
{
get { return Content as TextBlock; }
set { Content = value as TextBlock; }
}
public HighlightTextBlock()
{
TextContent = new TextBlock();
SetContent();
}
private void SetContent()
{
//TextContent.Text = Text;
var tmpText = Text;
var tmpHighlightText = HighlightText;
/*Task.Factory.StartNew<CombinedText>(() => GetCombined(txt, hghlghtTxt))
.ContinueWith(
x =>
{
Debug.WriteLine("------- XXXXXXXX -------");
var text = (CombinedText)x.Result;
TextContent = new TextBlock();
TextContent.Inlines.Add(new Run(text.Before ?? ""));
TextContent.Inlines.Add(new Run(text.Match ?? "") { Background = HighlightBrush });
TextContent.Inlines.Add(new Run(text.After ?? ""));
Debug.WriteLine("---------ZZZZZZZZ------------");
}
,TaskScheduler.FromCurrentSynchronizationContext()
);*/
Dispatcher.BeginInvoke(
(ThreadStart)delegate
{
var text = GetCombined(tmpText, tmpHighlightText);
TextContent = new TextBlock();
TextContent.Inlines.Add(new Run(text.Before ?? ""));
TextContent.Inlines.Add(new Run(text.Match ?? "") { Background = HighlightBrush });
TextContent.Inlines.Add(new Run(text.After ?? ""));
}
);
}
private CombinedText GetCombined(string text, string highlightText)
{
Debug.WriteLine("------------1111---------------");
var result = new CombinedText();
SharpDebug.WriteLine(text);
SharpDebug.WriteLine(highlightText);
if (text != null && highlightText != null)
{
Debug.WriteLine("-----------2222----------------");
var queryLength = highlightText.Length;
var sourceLength = text.Length;
var index = text.IndexOf(highlightText, StringComparison.InvariantCultureIgnoreCase);
if (index >= 0)
{
Debug.WriteLine("-------------3333--------------");
var stringBefore = text.Substring(0, index);
var stringMatch = text.Substring(index, queryLength);
var stringAfter = text.Substring(index + queryLength, sourceLength - (index + queryLength));
if (stringBefore.Length > 0)
{
Debug.WriteLine("-------------4444--------------");
result.Before = stringBefore;
}
if (stringMatch.Length > 0)
{
Debug.WriteLine("------------5555---------------");
result.Match = stringMatch;
}
if (stringAfter.Length > 0)
{
Debug.WriteLine("-------------6666--------------");
result.After = stringAfter;
}
Debug.WriteLine("------------7777---------------");
return result;
}
}
Debug.WriteLine("-------------9999--------------");
result.Before = text;
return result;
}
}
internal struct CombinedText
{
public string Before { get; set; }
public string Match { get; set; }
public string After { get; set; }
}
internal static class ControlExtensions
{
public static void Clear(this TextBlock text)
{
text.Text = "";
}
}

我试图加快执行速度。结果比原始版本更快,尽管它仍然不完美。
更新:我想到了另外两个澄清。
首先,您可以将旧的部分与新的部分进行比较,如果没有任何变化,请不要启动昂贵的多线程操作:
然后,你可以在更“平静”的生活阶段发送变化
Dispatcher'a。在这种情况下,Task您根本无法将其带入主要上下文:我机器上的这个选项表现得更好,尤其是在
HighlightText更改时没有真正改变的情况下。