2017-12-18 330 views
1

我正在爲我的WPF應用程序創建一個自定義控件。這是我的代碼:C#WPF不間斷地調用OnRender

MainWindow.xaml.cs:

public sealed class MainTimer : FrameworkElement 
{ 
    public DispatcherTimer Timer = new DispatcherTimer(); 

    public MainTimer() 
    { 
     Timer.Tick += delegate 
     { 
      UpdateLayout(); 

      // No luck 
      // Dispatcher.Invoke(delegate { },DispatcherPriority.Render); 

      // InvalidateVisual(); 
     }; 
     Timer.Interval = new TimeSpan(10); 
     Timer.Start(); 
    } 

    protected override void OnRender(DrawingContext drawingContext) 
    { 
     string mode = "12"; 

     Console.WriteLine("RENDERING"); 


     if (Application.Current.MainWindow != null) 
     { 
      if (mode == "24") 
      { 
       //drawingContext.DrawRectangle(new SolidColorBrush(Color.FromArgb(50,150,255,255)), null, BoundsRelativeTo(this, Application.Current.MainWindow)); 
       drawingContext.DrawText(new FormattedText(DateTime.Now.ToLongTimeString(), System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Microsoft PhagsPa"), 50, new SolidColorBrush(Color.FromArgb(50, 235, 255, 255))), new Point(0, -15)); 
      } 
      else 
      { 
       string st = ""; 

       if (DateTime.Now.Hour > 12) 
       { 
        st = ((DateTime.Now.Hour - 12).ToString("00") + " : " + DateTime.Now.Minute.ToString("00") + " : " + DateTime.Now.Second.ToString("00")) + " pm" ; 
       } 
       else 
       { 
        st = ((DateTime.Now.Hour).ToString("00") + " : " + DateTime.Now.Minute.ToString("00") + " : " + DateTime.Now.Second.ToString("00")) + " am"; 
       } 


       drawingContext.DrawText(new FormattedText(st, System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Microsoft PhagsPa"), 40, new SolidColorBrush(Color.FromArgb(50, 200, 255, 255))), new Point(0, -12)); 
      } 
     } 
     //Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle, null); 

    } 

    public static Rect BoundsRelativeTo(FrameworkElement element,Visual relativeTo) 
    { 
     return 
      element.TransformToVisual(relativeTo) 
       .TransformBounds(LayoutInformation.GetLayoutSlot(element)); 
    } 

} 

MainWindow.xaml:

<Window x:Class="WpfApp1.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:WpfApp1" 
    mc:Ignorable="d" 
    ShowInTaskbar="False" 
    AllowsTransparency="True" WindowStyle="None" 
    WindowStartupLocation="Manual" 
    Left="1168" 
    Top="120" 
    ResizeMode="NoResize" 
    WindowState="Normal" 
    Title="MainWindow" Height="75.132" Width="283.621" FontFamily="Microsoft PhagsPa"> 
<Window.Background> 
    <SolidColorBrush Opacity="0" Color="LightCyan"/> 
</Window.Background> 

<local:MainTimer Loaded="Grid_Loaded"/> 

的問題是 「的渲染」 如果信息每秒出現在控制檯中,但它只出現一次! 我希望我的控件每秒重新渲染一次。
我試過使用InvalidateVisual(),但程序佔用了我CPU資源的近70%-80%。
如何在不使用大量系統資源的情況下重新呈現控件?
在WinForm中是否有類似於「Refresh()」的方法?

感謝提前:)

+0

您似乎沒有在渲染過程中做任何您無法在XAML中執行的操作。你是否有理由想要繞過WPF並自己做?每秒設置*值*並讓WPF執行UI繪圖似乎是一件更容易的任務。 – nvoigt

+0

好吧我會嘗試使用標籤來做到這一點,但我仍然想知道如何更新UI而沒有滯後,謝謝您的評論。 – Ben

+0

順便說一句:你的Timespan是10 * ticks *。這真是太快了。你需要的東西可以做到60000 FPS左右。確保使用需要幾秒或者幾毫秒的構造函數。 – nvoigt

回答

1

你的設置,使這個非常微弱的,但你可以看到的時間,如果你知道如何尋找:

enter image description here

下面的代碼工作正常:

using System; 

namespace WpfApp1 
{ 
    using System.Windows; 
    using System.Windows.Media; 
    using System.Windows.Threading; 

    public sealed class MainTimer : FrameworkElement 
    { 
     private DispatcherTimer Timer = new DispatcherTimer(); 

     public MainTimer() 
     { 
      // what you are looking for is InvalidateVisual 
      this.Timer.Tick += (sender, args) => this.InvalidateVisual(); 

      // changed your timespan to a more appropriate value 
      this.Timer.Interval = TimeSpan.FromSeconds(1); 
      this.Timer.Start(); 
     } 

     protected override void OnRender(DrawingContext drawingContext) 
     { 
      string mode = "12"; 

      System.Diagnostics.Trace.WriteLine("Rendering"); 

      if (Application.Current.MainWindow != null) 
      { 
       if (mode == "24") 
       { 
        drawingContext.DrawText(new FormattedText(DateTime.Now.ToLongTimeString(), System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Microsoft PhagsPa"), 50, new SolidColorBrush(Color.FromArgb(50, 235, 255, 255))), new Point(0, -15)); 
       } 
       else 
       { 
        string st = ""; 

        if (DateTime.Now.Hour > 12) 
        { 
         st = ((DateTime.Now.Hour - 12).ToString("00") + " : " + DateTime.Now.Minute.ToString("00") + " : " + DateTime.Now.Second.ToString("00")) + " pm"; 
        } 
        else 
        { 
         st = ((DateTime.Now.Hour).ToString("00") + " : " + DateTime.Now.Minute.ToString("00") + " : " + DateTime.Now.Second.ToString("00")) + " am"; 
        } 


        drawingContext.DrawText(new FormattedText(st, System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Microsoft PhagsPa"), 40, new SolidColorBrush(Color.FromArgb(50, 200, 255, 255))), new Point(0, -12)); 
       } 
      } 
     } 
    } 
} 

使用XAML:

<Window x:Class="WpfApp1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:WpfApp1" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <local:MainTimer/> 
    </Grid> 
</Window> 

它每秒渲染一次。

我仍然認爲這不是定製的渲染是意味着,你可以用一個定時變更您的視圖模型爲此在XAML。但是,如果它變得更加複雜,您可能會對this other thread感興趣,並且詳細說明如何使用繪圖組提高性能的答案。

+0

順便說一句:這個應用程序用於我的桌面小工具,所以我將顏色設置爲透明。謝謝你回答我的問題 ! – Ben