簡體   English   中英

WPF:在后台不斷更新 UI

[英]WPF: Constanly Update UI in the background

我目前正在嘗試不斷更改背景中按鈕的顏色。 我目前在與 UI 相同的線程中更新按鈕。 這會嚴重減慢 UI 元素的使用速度。 我試過做后台工作人員,但我無法讓它連續做。 它只在開始時更新一次。 這是我現在正在做的偽代碼。

   private void UpdateButton(object sender, EventArgs e)
        {
            foreach (object obj in ButtonGrid.Children)
            {
              if (obj != null && obj.HasColor)
                {
                  if (obj.State.ON){
                   obj.Color = obj.color_off;
                  }
                  else{
                    obj.Color = new RadialGradientBrush(((SolidColorBrush)Brushes.White).Color, ((SolidColorBrush)obj.color_on).Color)
                  }
                }
            }
        }

     public MainWindow()
        {
          InitializeComponent();

          if (!InitializeSkinning())
          {
            ErrorAndExitNoPipe();
          }
          m_timer = new DispatcherTimer();
          m_timer.Tick += UpdateButton;
          m_timer.Start();
        }

我是如何嘗試做后台工作的。

private void UpdateButton(object sender, EventArgs e)
    {
        foreach (object obj in ButtonGrid.Children)
        {
          if (obj != null && obj.HasColor)
            {
              if (obj.State.ON){
               obj.Color = obj.color_off;
              }
              else{
                obj.Color = new RadialGradientBrush(((SolidColorBrush)Brushes.White).Color, ((SolidColorBrush)obj.color_on).Color)
              }
            }
        }
    }

 public MainWindow()
    {
      InitializeComponent();

      if (!InitializeSkinning())
      {
        ErrorAndExitNoPipe();
      }
     worker = new BackgroundWorker();
      worker.DoWork += (sender, e) => {
        //UpdateButton(sender, e);
      };
      worker.RunWorkerCompleted += (sender, eventArgs) => {
        UpdateButton(sender, eventArgs);
      };
      worker.RunWorkerAsync();
    }

編輯添加 XAML 代碼

它只是一個我用顏色填充並用作按鈕的網格。

<!-- Button Grid-->
        <Grid x:Name="ButtonGrid" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="1" Grid.RowSpan="3">
          <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
          </Grid.RowDefinitions>
          <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
        </Grid>

我正在解析 XML 文件以了解按鈕的圖像和每個按鈕的功能。 我只需要更改它們連續啟用或禁用的邊界顏色。

private void ParseButton(XmlNode button_node)
    {
        if (button_node.Name == "button")
        {
            int row_num = 1;
            XmlAttribute row_num_attr = button_node.Attributes["row"];
            if (row_num_attr != null)
            {
                try { row_num = Convert.ToInt32(row_num_attr.Value); } finally { }
            }

            int col_num = 1;
            XmlAttribute col_num_attr = button_node.Attributes["column"];
            if (col_num_attr != null)
            {
                try { col_num = Convert.ToInt32(col_num_attr.Value); } finally { }
            }

            Button Button = new Button();
            Button.HorizontalAlignment = HorizontalAlignment.Center;
            Button.VerticalAlignment = VerticalAlignment.Center;

            Button.PreviewMouseDown += PushButton;
            Button.PreviewMouseUp += ReleaseButton;

            Grid.SetRow(Button, row_num - 1);
            Grid.SetColumn(Button, col_num - 1);

            Button.BorderBrush = Brushes.Gray;
            Button.BorderThickness = new Thickness(0);
            Button.ButtonBackground = Brushes.Transparent;

            ParsePlcInfo(Button, button_node);

            string overlay_string = "";
            DirectoryInfo di = new DirectoryInfo(@"resources\\Buttons\" + button_node.InnerText);
            FileInfo[] files = di.GetFiles("*");
            foreach (FileInfo file in files)
            {
                if (System.IO.Path.GetFileNameWithoutExtension(file.Name) == button_node.InnerText)
                {
                    if (file.Extension == ".xml")
                    {
                        continue;
                    }
                    else if (file.Extension == ".xaml")
                    {
                        Viewbox vb = new Viewbox();
                        Canvas canvas = XamlReader.Load(new StreamReader(file.FullName).BaseStream) as Canvas;
                        vb.Child = canvas;
                        Canvas.SetZIndex(vb, -1);
                        Button.contentGrid.Children.Add(vb);
                        break;
                    }
                    else if (file.Extension == ".svg")
                    {
                        overlay_string = @"resources\\Buttons\" + button_node.InnerText + @"\" + button_node.InnerText + ".svg";
                        Image image = new Image() { Source = SvgReader.Load(new StreamReader(overlay_string).BaseStream) };
                        Canvas.SetZIndex(image, -1);
                        try { Button.contentGrid.Children.Add(image); } finally { }
                        break;
                    }
                }
            }

            ButtonGrid.Children.Add(Button);
        }
    }

如果我沒記錯的話,工人會做它的工作並完成。 由於您沒有在任何地方循環,它會調用一次“UpdateButton”方法並停止工作。

worker.DoWork += (sender, e) => {
    while (true)
    {
        UpdateButton(sender, e);
    }
};

與此類似的事情應該可以解決您的問題。 也許添加一些 Thread.Sleep() 以便您不會多次執行該方法。

UI 元素必須在 UI 線程上更新,這是沒有辦法的。 使用后台線程最多可以將確定新顏色的計算放入后台,然后僅調用 UI 線程進行實際更新。 但是,從那里的代碼來看,實際上沒有多少“計算”可言,所以我懷疑這對您有多大幫助。

在不知道ButtonGrid是什么的情況下很難肯定地說,但是使用DataTemplate s、 Style s 和DataTrigger s 似乎可以更好地完成您想要做的事情。 您可以為視覺元素創建Style ,其中DataTrigger將根據其他屬性設置顏色。 這將更符合 WPF 的設計使用方式。

話雖如此,如果您堅持這樣做,您可能可以通過使用Dispatcher.Invoke(Action, DispatcherPriority)來提高響應速度。 使用它,您可以告訴 WPF 框架以較低的DispatcherPriority運行每個顏色更新,這應該為用戶輸入提供優先權。 下面是一個例子:

    private void UpdateButton(object sender, EventArgs e)
    {
        foreach (object obj in ButtonGrid.Children)
        {
            Application.Current.Dispatcher.Invoke(() =>
            {
                if (obj != null && obj.HasColor)
                {
                    if (obj.State.ON)
                    {
                        obj.Color = obj.color_off;
                    }
                    else
                    {
                        obj.Color = new RadialGradientBrush(((SolidColorBrush)Brushes.White).Color, ((SolidColorBrush)obj.color_on).Color);
                    }
                }
            }, System.Windows.Threading.DispatcherPriority.Background);
        }
    }

上面的代碼將在不使用后台工作者的情況下運行。 並且應該在循環中的每個obj之間處理用戶輸入。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM