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