【发布时间】:2021-11-09 18:41:05
【问题描述】:
我正在开发一个使用 Xceed BusyIndicator 的小型 WPF 应用程序。我在动态更新加载消息时遇到了一些问题,因为内容包含在 DataTemplate 中。我熟悉的数据绑定或设置文本值的方法不起作用。
我已经进行了一些研究 - 看起来其他人也遇到了这个问题。似乎是answered here,但由于答案不在上下文中,我无法完全弄清楚它在我的代码中是如何工作的。
这是我的示例代码,如果有人可以帮助我了解我所缺少的内容,我将不胜感激。这增加了使用 BackgroundWorker 线程的挑战。我使用它是因为我预计这将是一个长期的进程——最终该操作将启动一个 SQL 作业,该作业将处理可能需要长达 15 分钟的项目。我的计划是让线程定期运行存储过程来获取剩余项目的计数以处理和更新加载消息。
MainWindow.xaml:
<Window x:Class="WPFTest.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:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:local="clr-namespace:WPFTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<xctk:BusyIndicator x:Name="AutomationIndicator">
<xctk:BusyIndicator.BusyContentTemplate>
<DataTemplate>
<StackPanel Margin="4">
<TextBlock Text="Sending Invoices" FontWeight="Bold" HorizontalAlignment="Center"/>
<WrapPanel>
<TextBlock Text="Items remaining: "/>
<TextBlock x:Name="_ItemsRemaining" Text="{Binding Path=DataContext.ItemsRemaining, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"/>
</WrapPanel>
</StackPanel>
</DataTemplate>
</xctk:BusyIndicator.BusyContentTemplate>
<Grid>
<StackPanel>
<TextBlock Text="Let's test this thing" />
<Button x:Name="_testBtn" Content="Start" Width="100" HorizontalAlignment="Left" Click="testBtn_Click"/>
<TextBlock Text="{Binding ItemsRemaining}"/>
</StackPanel>
</Grid>
</xctk:BusyIndicator>
</Window>
MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WPFTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
UpdateItemsRemaining(0);
}
public class ItemCountDown
{
//One Idea was to try and set a data binding variable
public string ItemsRemaining { get; set; }
}
public void UpdateItemsRemaining(int n)
{
ItemCountDown s = new ItemCountDown();
{
s.ItemsRemaining = n.ToString();
};
//this.AutomationIndicator.DataContext = s; Works during initiation, but not in the thread worker.
}
private void testBtn_Click(object sender, RoutedEventArgs e)
{
//Someone clicked the button, run the Test Status
TestStatus();
}
public void TestStatus()
{
// Normally I'd start a background worker to run a loop to check that status in SQL
BackgroundWorker getStatus = new BackgroundWorker();
getStatus.DoWork += (o, ea) =>
{
//Normally there's a sql connection being opened to check a SQL Job, and then I run a loop that opens the connection to check
//the status until it either fails or successfully ended.
//but for this test, I'll just have it run for 15 seconds, counting down fake items.
int fakeItems = 8;
do //
{
//Idea One - write to the text parameter. But can't find it in the template
//Dispatcher.Invoke((Action)(() => _ItemsRemaining.Text = fakeItems));
//Idea two - use data binding to update the value. Data binding works just find outside of the Data Template but is ignored in the template
UpdateItemsRemaining(fakeItems);
//subtract one from fake items and wait a second.
fakeItems--;
Thread.Sleep(1000);
} while (fakeItems > 0);
};
getStatus.RunWorkerCompleted += (o, ea) =>
{
//work done, end it.
AutomationIndicator.IsBusy = false;
};
AutomationIndicator.IsBusy = true;
getStatus.RunWorkerAsync();
}
}
}
感谢您的审阅,感谢您提供的任何帮助或指导。
【问题讨论】:
标签: c# wpf data-binding backgroundworker busyindicator