我正在使用C#WPF。
我试图弄清楚是否有办法更新 XAML 元素,而不必使用您在以下代码中看到的 Refresh()
方法。
现在,我将包含与 C# doPlay()
方法相关的代码,该方法通过线程和 XAML 代码在 MainWindow 中启动。
任何人都可以建议一种无需使用 Refresh()
方法即可更新进度条的方法吗?
private void doPlay()
{
Transfers.Add(new Transfer(Utils.RandomString(6), Utils.RandomString(6), Transfer.Type_t.download, "Red"));
Transfers.Add(new Transfer(Utils.RandomString(6), Utils.RandomString(6), Transfer.Type_t.download, "Blue"));
Transfers.Add(new Transfer(Utils.RandomString(6), Utils.RandomString(6), Transfer.Type_t.download, "Yellow"));
Transfers.Add(new Transfer(Utils.RandomString(6), Utils.RandomString(6), Transfer.Type_t.download, "Cyan"));
Transfers.Add(new Transfer(Utils.RandomString(6), Utils.RandomString(6), Transfer.Type_t.download, "Black"));
Transfers.Add(new Transfer(Utils.RandomString(6), Utils.RandomString(6), Transfer.Type_t.download, "Brown"));
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
TransfersXAML.ItemsSource = Transfers;
}));
Random rnd = new Random();
for (var i = 0; i < 100 * Transfers.Count; i++)
{
var next = rnd.Next(0, Transfers.Count);
mre.WaitOne();
int index = next;
if (Transfers[index].CurrentStep < 100)
{
Thread.Sleep(100);
Transfers[index].CurrentStep++;
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
TransfersXAML.Items.Refresh();
}));
}
else i--;
}
}
XAML 相对代码:
<UniformGrid x:Name="DownLeftPanel" Grid.Column="2" Grid.Row="2">
<ListBox x:Name="TransfersXAML" HorizontalContentAlignment="Stretch" ItemsSource="{Binding Transfers}">
<ListBox.ItemTemplate>
<DataTemplate>
<ProgressBar Height="30" Minimum="0" Maximum="{Binding NSteps}"
Value="{Binding CurrentStep}" Foreground="{Binding Color}" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Get info" Click="GetTransferInfoClick" />
<MenuItem Header="Cancel" Click="CancelTransferClick" />
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
</UniformGrid>
我试图简单地从 BeginInvoke 中删除操作,但通过这种方式不再显示栏,即从第一个发布的代码中删除这些说明:
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
TransfersXAML.Items.Refresh();
}));
这个问题与以下问题有关:网络线程阻塞 GUI,特别是参考问题本身下方的评论。
如果Transfers
类实现 INotifyPropertyChanged 接口并在 CurrentStep
属性的 setter 中引发 PropertyChanged
事件,则只需在后台线程上设置此属性,而无需调用 Refresh()
方法:
for (var i = 0; i< 100 * Transfers.Count; i++)
{
var next = rnd.Next(0, Transfers.Count);
mre.WaitOne();
int index = next;
if (Transfers[index].CurrentStep < 100)
{
Thread.Sleep(100);
Transfers[index].CurrentStep++;
}
else i--;
}