2010-07-07 6 views
7

Trong một giao diện người dùng WPF Tôi có nút nối với nhau bằng những con đường Bút chì, như vậy:WPF PathGeometry cập nhật _SLOW_

It might be... atomic http://nv3wrg.blu.livefilestore.com/y1pIGBd33lCC6lF-9H0MqgnL40BdNEoEemZDENzgpEI1IL2j4B-qb3qS3WlxMSys28IjqNngR7mdfvQBnPzerf4cFJQj9VqHBh4/acurve.png?psid=1

Khi người dùng kéo một nút xung quanh, các đường dẫn kết nối cần phải được cập nhật trong gian thực thời gian. Tuy nhiên, tôi đã nhận thấy một số chậm lại (đặc biệt là nếu một nút được kết nối với nhiều nút khác, hoặc nhiều nút đang được kéo cùng một lúc). Tôi cấu hình nó, và vấn đề chính dường như là ở đây:

Proof I actually used a profiler, so please don't be all like "OMG, premature opiumzation; you are DEMON!!" http://nv3wrg.blu.livefilestore.com/y1pjRfQYuN57yei5qdUxW4Dlh4vVCzPy8TcfEzlw_8cUicfOR6BwHCTntcQbQUspRAgBdKcItC0ZcEJbIWMKaYrCtDMOtCBKB4g/profile.png?psid=1

Đây là chức năng đó được gọi là mỗi lần một trong hai nguồn hoặc đích sở hữu được thay đổi. Hình học tạo nên đường dẫn dường như đang được tái tạo bên trong mỗi khi bất kỳ điểm điều khiển nào thay đổi. Có lẽ nếu có một cách để ngăn chặn hình học được tái tạo cho đến sau khi tất cả các thuộc tính phụ thuộc có liên quan đã được thiết lập?

CHỈNH SỬA: Giải pháp của Mart để sử dụng StreamGeometry tăng tốc theo cấp số nhân; chức năng là hư không gần với một nút cổ chai. Một chút Phản ánh cho thấy rằng PathGeometry sử dụng StreamGeometry nội bộ, và mỗi khi bất kỳ thuộc tính phụ thuộc nào được thay đổi, StreamGeometry được tính toán lại. Vì vậy, cách này chỉ cắt giảm trung gian. Kết quả cuối cùng là:

private void onRouteChanged() 
{ 
    Point src = Source; 
    Point dst = Destination; 
    if (!src.X.isValid() || !src.Y.isValid() || !dst.X.isValid() || !dst.Y.isValid()) 
    { 
     _shouldDraw = false; 
     return; 
    } 

    /* 
     * The control points are all laid out along midpoint lines, something like this: 
     * 
     * -------------------------------- 
     * |   |   |   | 
     * | SRC | CP1 |   | 
     * |   |   |   | 
     * -------------------------------- 
     * |   |   |   | 
     * |   | MID |   | 
     * |   |   |   | 
     * ------------------------------- 
     * |   |   |   | 
     * |   | CP2 | DST | 
     * |   |   |   | 
     * -------------------------------- 
     * 
     * This causes it to be horizontal at the endpoints and vertical 
     * at the midpoint. 
     */ 

    double mx = (src.X + dst.X)/2; 
    double my = (src.Y + dst.Y)/2; 
    Point mid = new Point(mx, my); 
    Point cp1 = new Point(mx, src.Y); 
    Point cp2 = new Point(mx, dst.Y); 

    _geometry.Clear(); 
    _shouldDraw = true; 
    using(StreamGeometryContext ctx = _geometry.Open()) 
    { 
     ctx.BeginFigure(src, false, false); 
     ctx.QuadraticBezierTo(cp1, mid, true, false); 
     ctx.QuadraticBezierTo(cp2, dst, true, false); 
    } 
} 

Mã nguồn đầy đủ của dự án có sẵn tại http://zeal.codeplex.com cho tò mò.

Trả lời

7

1- Tôi sẽ cố gắng sử dụng StreamGeometry:

 StreamGeometry streamGeo = new StreamGeometry(); 
     Stopwatch sw = new Stopwatch(); 
     sw.Start(); 
     for (int i = 0; i < 10000; i++) 
     { 
      streamGeo.Clear(); 
      var ctx = streamGeo.Open(); 
      ctx.BeginFigure(new Point(0, 0), false, false); 
      ctx.QuadraticBezierTo(new Point(10, 10), new Point(10, i), true, true); 
      ctx.Close(); 
     } 
     sw.Stop(); 
     Console.WriteLine(sw.ElapsedMilliseconds); // For 10k it took 30 ms 

Có vẻ nhanh hơn nhiều so PathGeometry + PathFigure.

Khi bạn đặt Điểm cho số QuadraticBezierSegment, nó sẽ tính toán lại mọi thứ. Đó là lý do tại sao nó chậm. Và chậm hơn khi nó đã được thêm vào một hình học.

2- Cố gắng chỉ sử dụng 1 khung khuôn khổ cho tất cả các đường cong của bạn. Kiểm tra điều này: Writing More Efficient ItemsControls

+0

Cảm ơn; chuyển sang StreamGeometry dường như để giải quyết vấn đề! –

0

Nếu bạn không cần thử nghiệm truy cập, menu ngữ cảnh, chú giải công cụ cho đường cong, bạn có thể sử dụng hình ảnh đơn giản thay vì các yếu tố khung.

+0

Cảm ơn! Nhưng nó nằm trên một Canvas, vì vậy ít nhất nó phải là một UIElement (để được trên một bảng điều khiển). Và vì thuộc tính thay đổi làm mất hiệu lực render, cách dễ nhất để làm điều này là thông qua FrameworkPropertyMetadataOptions.AffectsRender, đòi hỏi một FraworkElement. Dù sao, làm thế nào điều này sẽ giúp giải quyết vấn đề trên? –

0

Tôi sẽ tưởng tượng rằng vấn đề hiệu suất của bạn đến từ giảm dần từ FrameworkElement và có công cụ bố cục WPF tính lại bố cục khi đường cong được tính toán.

Những gì bạn có thể xem xét là mô hình đường cong bằng cách giảm dần từ Freezable và sau đó sử dụng FrameworkElement (như PathGeometry) để hiển thị hình học thực tế.

+0

Bố trí thực sự chỉ được tính toán lại khi nguồn hoặc đích thay đổi, nhưng nếu người dùng đang kéo một nút, điều này có thể là mỗi khi chuột di chuyển gấp số lần đường dẫn bị ảnh hưởng. Con đường không bị đóng băng, vì vậy nó không thể xuống từ freezable. –

+1

Freezable không có nghĩa là bạn không thể thay đổi nó - bạn không thể thay đổi nó sau khi nó bị đóng băng. Tôi tưởng tượng nó có thể sao chép, thay đổi đường cong, đóng băng hình học và cập nhật FrameworkElement có chứa nó nhanh hơn nhiều nếu bạn thực hiện một FrameworkElement làm tất cả. Cuối cùng, tôi chỉ nghĩ rằng sẽ không có cách nào để có được hiệu suất chấp nhận được từ việc sử dụng FrameworkElement làm cơ sở. – codekaizen