WPF: постоянное обновление пользовательского интерфейса в фоновом режиме - PullRequest
0 голосов
/ 10 января 2020

Я сейчас пытаюсь непрерывно менять цвет кнопок на заднем плане. В настоящее время у меня есть кнопки обновления в той же теме, что и пользовательский интерфейс. Это сильно замедляет использование элементов пользовательского интерфейса. Я пытался делать фоновые рабочие, но я не могу заставить это постоянно делать это. Он просто обновляет их один раз при запуске. Вот псевдокод того, что я делаю сейчас.

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

Ответы [ 2 ]

0 голосов
/ 10 января 2020

Элементы пользовательского интерфейса должны быть обновлены в потоке пользовательского интерфейса, нет никакого способа обойти это. Максимум, что вы могли бы сделать с фоновым потоком, - это поместить вычисления, определяющие новый цвет, в фон, а затем вызвать только поток пользовательского интерфейса для фактического обновления. Однако, судя по коду, на самом деле не так много «вычислений», о которых можно было бы говорить, поэтому я сомневаюсь, что это сильно вам поможет.

Трудно сказать наверняка, не зная, что такое 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 в l oop.

0 голосов
/ 10 января 2020

Если я не ошибаюсь, работник выполнит свою работу и закончит sh. Поскольку вы нигде не зацикливаетесь, он вызовет метод «UpdateButton» один раз и перестанет работать.

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

Что-то вроде этого должно быть решением вашей проблемы. Возможно, добавьте Thread.Sleep (), чтобы метод не выполнялся слишком много раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...