本文介绍了10000的+ UI元素,绑定或绘制?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在绘制时间轴控件的标题。
看起来像这样:



我每行0.01毫秒,所以10分钟的时间线我正在绘制60000行+ 6000标签。
这需要一段时间,〜10秒。
我想从UI线程卸载这个。
我的代码是:

  private void drawHeader()
{
Header.Children 。明确();
switch(viewLevel)
{
case ViewLevel.MilliSeconds100:
double hWidth = Header.Width;
this.drawHeaderLines(new TimeSpan(0,0,0,0,10),100,5,hWidth);

//正在调查后台工作负载UI

// backgroundWorker = new BackgroundWorker();

//backgroundWorker.DoWork + = delegate(object sender,DoWorkEventArgs args)
// {
// this.drawHeaderLines(new TimeSpan(0,0,0,0 ,10),100,5,hWidth);
//};
//backgroundWorker.RunWorkerAsync();
break;
}
}

private void drawHeaderLines(TimeSpan timeStep,int majorEveryXLine,int distanceBetweenLines,double headerWidth)
{
var currentTime = new TimeSpan ,0,0,0,0);
const int everyXLine100 = 10;
double currentX = 0;
var currentLine = 0;
while(currentX< headerWidth)
{
var l = new Line
{
ToolTip = currentTime.ToString(@hh\:mm\: ss \.fff),
StrokeThickness = 1,
X1 = 0,
X2 = 0,
Y1 = 30,
Y2 = 25
};
if(((currentLine%majorEveryXLine)== 0)&& currentLine!= 0)
{
l.StrokeThickness = 2;
l.Y2 = 15;
var textBlock = new TextBlock
{
Text = l.ToolTip.ToString(),
FontSize = 8,
FontFamily = new FontFamily(Tahoma),
Foreground = new SolidColorBrush(Color.FromRgb(255,255,255))
};

Canvas.SetLeft(textBlock,(currentX - 22));
Canvas.SetTop(textBlock,0);
Header.Children.Add(textBlock);
}

if(((currentLine%everyXLine100)== 0)&& currentLine!= 0)
&&(currentLine%majorEveryXLine)!= 0)
{
l.Y2 = 20;
var textBlock = new TextBlock
{
Text = string.Format(。{0},TimeSpan.Parse(l.ToolTip.ToString())。毫秒),
FontSize = 8,
FontFamily = new FontFamily(Tahoma),
Foreground = new SolidColorBrush(Color.FromRgb(192,192,192))
};

Canvas.SetLeft(textBlock,(currentX - 8));
Canvas.SetTop(textBlock,8);
Header.Children.Add(textBlock);
}
l.Stroke = new SolidColorBrush(Color.FromRgb(255,255,255));
Header.Children.Add(l);
Canvas.SetLeft(l,currentX);

currentX + = distanceBetweenLines;
currentLine ++;
currentTime + = timeStep;
}
}

我查看了BackgroundWorker,除了你不能在非UI线程上创建UI元素。



是否可以在非UI线程中执行drawHeaderLines?



我可以使用数据绑定来绘制线条吗?
这将有助于UI响应?



我可以想象我可以使用数据绑定,但是Styling可能超出了我目前的WPF能力(来自winforms,并试图了解所有这些样式对象和绑定它们)。



有人可以提供一个引人入胜的起点吗?或者Google一个可以让我开始的教程?

解决方案

我把它放在后面一点点, / p>

但我想我已经提出了一个解决方案。



使用DrawingVisual和DrawingContext。



这篇博客文章对我有帮助:



首先我们需要得到我们的Visual类这个代码已经被打了,清理是个好主意):

  public class MyVisualHost:FrameworkElement 
{
私有readonly VisualCollection小孩;

public MyVisualHost(int width)
{
children = new VisualCollection(this);

var visual = new DrawingVisual();
children.Add(visual);

var currentTime = new TimeSpan(0,0,0,0,0);
const int everyXLine100 = 10;
double currentX = 0;
var currentLine = 0;
double distanceBetweenLines = 5;
TimeSpan timeStep = new TimeSpan(0,0,0,0,10);
int majorEveryXLine = 100;

var grayBrush = new SolidColorBrush(Color.FromRgb(192,192,192));
grayBrush.Freeze();
var grayPen = new Pen(grayBrush,2);
var whitePen = new Pen(Brushes.White,2);
grayPen.Freeze();
whitePen.Freeze();

使用(var dc = visual.RenderOpen())
{
while(currentX< width)
{
if(((currentLine% ($)
{
dc.DrawLine(whitePen,new Point(currentX,30),new Point(currentX,15));

var text = new FormattedText(
currentTime.ToString(@hh\:mm\:ss\ffff),
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(Tahoma),
8,
grayBrush);

dc.DrawText(text,new Point((currentX - 22),0));
}
else if((((CurrentLine%everyXLine100)== 0)&& currentLine!= 0)
&&(currentLine%majorEveryXLine)!= 0)
{
dc.DrawLine(grayPen,new Point(currentX,30),new Point(currentX,20));

var text = new FormattedText(
string.Format(。{0},currentTime.Milliseconds),
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(Tahoma),
8,
grayBrush);
dc.DrawText(text,new Point((currentX - 8),8));
}
else
{
dc.DrawLine(grayPen,new Point(currentX,30),new Point(currentX,25));
}

currentX + = distanceBetweenLines;
currentLine ++;
currentTime + = timeStep;
}
}
}

//为VisualChildrenCount属性提供必需的覆盖。
protected override int VisualChildrenCount {get {return children.Count; }}

//为GetVisualChild方法提供必需的覆盖。
protected override Visual GetVisualChild(int index)
{
if(index< 0 || index> = children.Count)
{
throw new ArgumentOutOfRangeException );
}

return children [index];
}
}

接下来我们需要我们的绑定:

  public static readonly DependencyProperty HeaderDrawingVisualProperty = DependencyProperty.Register(HeaderDrawingVisual,typeof(MyVisualHost),typeof(MainWindow)); 

public MyVisualHost VisualHost
{
get {return(MyVisualHost)GetValue(HeaderDrawingVisualProperty); }
set {SetValue(HeaderDrawingVisualProperty,value); }
}

XAML:

 < Canvas x:Name =HeaderBackground =#FF2D2D30Grid.Row =0> 
< ContentPresenter Content ={Binding HeaderDrawingVisual}/>
< / Canvas>

然后只需在代码中设置:

  Header.Width = 50000; 
VisualHost = new MyVisualHost(50000);

我的测试显示,使用这种新方法的宽度为50000,我看到了很大的增长! / p>

 旧方式总计毫秒:277.061 
新方式总计毫秒:13.9982
旧方式总计毫秒:518.4632
新方式总计毫秒:12.9423
旧方式总计毫秒:479.1846
新方式总计毫秒:23.4987
旧方式总计毫秒:477.1366
新方式总计毫秒:12.6469
旧方式总计毫秒:481.3118
新方式总计毫秒:12.9678

时间是少于第一次,因为项目必须在重建时被清除。


I am drawing a header for a timeline control.It looks like this:

I go to 0.01 millisecond per line, so for a 10 minute timeline I am looking at drawing 60000 lines + 6000 labels.This takes a while, ~10 seconds.I would like to offload this from the UI thread.My code is currently:

private void drawHeader()
{
  Header.Children.Clear();
  switch (viewLevel)
  {
    case ViewLevel.MilliSeconds100:
        double hWidth = Header.Width;
        this.drawHeaderLines(new TimeSpan(0, 0, 0, 0, 10), 100, 5, hWidth);

        //Was looking into background worker to off load UI

        //backgroundWorker = new BackgroundWorker();

        //backgroundWorker.DoWork += delegate(object sender, DoWorkEventArgs args)
        //                               {
        //                                   this.drawHeaderLines(new TimeSpan(0, 0, 0, 0, 10), 100, 5, hWidth);
        //                               };
        //backgroundWorker.RunWorkerAsync();
        break;
    }
}

private void drawHeaderLines(TimeSpan timeStep, int majorEveryXLine, int distanceBetweenLines, double headerWidth)
{
var currentTime = new TimeSpan(0, 0, 0, 0, 0);
const int everyXLine100 = 10;
double currentX = 0;
var currentLine = 0;
while (currentX < headerWidth)
{
    var l = new Line
                {
                    ToolTip = currentTime.ToString(@"hh\:mm\:ss\.fff"),
                    StrokeThickness = 1,
                    X1 = 0,
                    X2 = 0,
                    Y1 = 30,
                    Y2 = 25
                };
    if (((currentLine % majorEveryXLine) == 0) && currentLine != 0)
    {
        l.StrokeThickness = 2;
        l.Y2 = 15;
        var textBlock = new TextBlock
                            {
                                Text = l.ToolTip.ToString(),
                                FontSize = 8,
                                FontFamily = new FontFamily("Tahoma"),
                                Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255))
                            };

        Canvas.SetLeft(textBlock, (currentX - 22));
        Canvas.SetTop(textBlock, 0);
        Header.Children.Add(textBlock);
    }

    if ((((currentLine % everyXLine100) == 0) && currentLine != 0)
        && (currentLine % majorEveryXLine) != 0)
    {
        l.Y2 = 20;
        var textBlock = new TextBlock
                            {
                                Text = string.Format(".{0}", TimeSpan.Parse(l.ToolTip.ToString()).Milliseconds),
                                                            FontSize = 8,
                                                            FontFamily = new FontFamily("Tahoma"),
                                                            Foreground = new SolidColorBrush(Color.FromRgb(192, 192, 192))
                            };

        Canvas.SetLeft(textBlock, (currentX - 8));
        Canvas.SetTop(textBlock, 8);
        Header.Children.Add(textBlock);
    }
    l.Stroke = new SolidColorBrush(Color.FromRgb(255, 255, 255));
    Header.Children.Add(l);
    Canvas.SetLeft(l, currentX);

    currentX += distanceBetweenLines;
    currentLine++;
    currentTime += timeStep;
}
}

I had looked into BackgroundWorker, except you can't create UI elements on a non-UI thread.

Is it possible at all to do drawHeaderLines in a non-UI thread?

Could I use data binding for drawing the lines?Would this help with UI responsiveness?

I would imagine I can use databinding, but the Styling is probably beyond my current WPF ability (coming from winforms and trying to learn what all these style objects are and binding them).

Would anyone be able to supply a starting point for tempting this out? Or Google a tutorial that would get me started?

解决方案

Well I had put this on the back burner for a little but.

But I think I have come up with a solution.

To use DrawingVisual and DrawingContext.

This blog post helped me quite a bit: Simple WPF 2D Graphics: DrawingVisual

First we need to get our Visual class (note this code has been slapped together, cleaning is a good idea):

public class MyVisualHost : FrameworkElement
{
private readonly VisualCollection children;

public MyVisualHost(int width)
{
    children = new VisualCollection(this);

    var visual = new DrawingVisual();
    children.Add(visual);

    var currentTime = new TimeSpan(0, 0, 0, 0, 0);
    const int everyXLine100 = 10;
    double currentX = 0;
    var currentLine = 0;
    double distanceBetweenLines = 5;
    TimeSpan timeStep = new TimeSpan(0, 0, 0, 0, 10);
    int majorEveryXLine = 100;

    var grayBrush = new SolidColorBrush(Color.FromRgb(192, 192, 192));
    grayBrush.Freeze();
    var grayPen = new Pen(grayBrush, 2);
    var whitePen = new Pen(Brushes.White, 2);
    grayPen.Freeze();
    whitePen.Freeze();

    using (var dc = visual.RenderOpen())
    {
        while (currentX < width)
        {
            if (((currentLine % majorEveryXLine) == 0) && currentLine != 0)
            {
                dc.DrawLine(whitePen, new Point(currentX, 30), new Point(currentX, 15));

                var text = new FormattedText(
                    currentTime.ToString(@"hh\:mm\:ss\.fff"),
                    CultureInfo.CurrentCulture,
                    FlowDirection.LeftToRight,
                    new Typeface("Tahoma"),
                    8,
                    grayBrush);

                dc.DrawText(text, new Point((currentX - 22), 0));
            }
            else if ((((currentLine % everyXLine100) == 0) && currentLine != 0)
                        && (currentLine % majorEveryXLine) != 0)
            {
                dc.DrawLine(grayPen, new Point(currentX, 30), new Point(currentX, 20));

                var text = new FormattedText(
                    string.Format(".{0}", currentTime.Milliseconds),
                    CultureInfo.CurrentCulture,
                    FlowDirection.LeftToRight,
                    new Typeface("Tahoma"),
                    8,
                    grayBrush);
                dc.DrawText(text, new Point((currentX - 8), 8));
            }
            else
            {
                dc.DrawLine(grayPen, new Point(currentX, 30), new Point(currentX, 25));
            }

            currentX += distanceBetweenLines;
            currentLine++;
            currentTime += timeStep;
        }
    }
}

// Provide a required override for the VisualChildrenCount property.
protected override int VisualChildrenCount { get { return children.Count; } }

// Provide a required override for the GetVisualChild method.
protected override Visual GetVisualChild(int index)
{
    if (index < 0 || index >= children.Count)
    {
        throw new ArgumentOutOfRangeException();
    }

    return children[index];
}
}

Next we need our binding:

public static readonly DependencyProperty HeaderDrawingVisualProperty = DependencyProperty.Register("HeaderDrawingVisual", typeof(MyVisualHost), typeof(MainWindow));

public MyVisualHost VisualHost
{
    get { return (MyVisualHost)GetValue(HeaderDrawingVisualProperty); }
    set { SetValue(HeaderDrawingVisualProperty, value); }
}

XAML:

<Canvas x:Name="Header" Background="#FF2D2D30" Grid.Row="0">
    <ContentPresenter Content="{Binding HeaderDrawingVisual}" />
</Canvas>

Then just set in code:

Header.Width = 50000;
VisualHost = new MyVisualHost(50000);

My testing showed, using a width of 50000 with this new method, I saw a great increase!

Old way Total Milliseconds: 277.061
New way Total Milliseconds: 13.9982
Old way Total Milliseconds: 518.4632
New way Total Milliseconds: 12.9423
Old way Total Milliseconds: 479.1846
New way Total Milliseconds: 23.4987
Old way Total Milliseconds: 477.1366
New way Total Milliseconds: 12.6469
Old way Total Milliseconds: 481.3118
New way Total Milliseconds: 12.9678

Time is less the first time because items have to be cleared when rebuild.

这篇关于10000的+ UI元素,绑定或绘制?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-02 21:54