代码之家  ›  专栏  ›  技术社区  ›  Ben

C#WPF连续无延迟地调用OnRender

  •  2
  • Ben  · 技术社区  · 7 年前

    我正在为我的WPF应用程序创建自定义控件。这是我的代码:

    主窗口。xaml。反恐精英:

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

    主窗口。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"/>
    

    问题是消息“RENDERING”应该每秒出现在控制台中,但它只出现一次! 我希望我的控件每秒都重新渲染。
    我试过使用 InvalidateVisual() ,但该程序占用了我将近70%-80%的CPU资源。
    如何在不使用大量系统资源的情况下重新呈现控件?
    WinForm中是否有类似于“Refresh()”的方法?

    提前感谢:)

    1 回复  |  直到 7 年前
        1
  •  2
  •   nvoigt    7 年前

    您的设置使其非常模糊,但如果您知道要查找什么,您可以看到时间:

    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中通过计时器更改viewmodel来执行此操作 价值 . 然而,如果情况变得更复杂,您可能会对 this other thread 以及详细说明如何使用绘图组提高性能的答案。