[英]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.