2017-12-18 3 views
1

Ich erstelle ein benutzerdefiniertes Steuerelement für meine WPF-App. Dies ist mein Code:C# WPF Aufruf OnRender kontinuierlich ohne Verzögerung

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"/> 

Das Problem ist, erscheint die Meldung "RENDERING" sollte erscheinen in der Konsole jede Sekunde, aber es erscheint nur einmal! Ich möchte meine Kontrolle jede Sekunde neu rendern.
Ich versuchte mit InvalidateVisual(), aber das Programm verbraucht fast 70% -80% meiner CPU-Ressourcen.
Wie kann ich meine Steuerung ohne viele Systemressourcen erneut rendern?
Gibt es eine ähnliche Methode wie "Aktualisieren()" in WinForm?

Vielen Dank im Voraus :)

+0

Sie scheinen nichts in Ihrem Rendering zu tun, was Sie in XAML nicht tun konnten. Gibt es einen Grund, warum du WPF umgehen und es selbst machen willst? Wenn Sie den * Wert * jede Sekunde setzen und es WPF erlauben, die UI-Zeichnung zu erstellen, scheint dies eine viel einfachere Aufgabe zu sein. – nvoigt

+0

Ok Ich werde versuchen, Label zu verwenden, aber ich möchte immer noch wissen, wie UI ohne Verzögerung zu aktualisieren, danke für Ihren Kommentar. – Ben

+0

BTW: Ihre Zeitspanne ist 10 * Ticks *. Das ist verdammt schnell. Sie würden etwas brauchen, das ungefähr 60000 FPS dafür tun könnte. Stellen Sie sicher, dass Sie einen Konstruktor verwenden, der Sekunden oder vielleicht Millisekunden dauert. – nvoigt

Antwort

1

Ihre Einstellungen machen dies sehr schwach, aber man kann die Zeit, sehen, wenn Sie wissen, was zu suchen:

enter image description here

Der folgende Code funktioniert:

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)); 
       } 
      } 
     } 
    } 
} 

Mit 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> 

Es wird jede Sekunde gerendert.

Ich denke immer noch, dass diese ist nicht, was benutzerdefinierte Rendering gemeint wurde, können Sie dies in XAML mit einem Timer tun können Ihre Viewmodel Wert zu ändern. Wenn es jedoch komplizierter wird, interessiert Sie möglicherweise this other thread und die Antwort, die Details beschreibt, wie die Leistung mit einer Zeichnungsgruppe verbessert wird.

+0

BTW: Diese App wird für mein Desktop-Gadget verwendet, also stelle ich die Farbe auf transparent. Danke für das Beantworten meiner Frage! – Ben

Verwandte Themen