我正在研究C#和WPF。
我正在开发一个应该在局域网上处理数据传输的应用程序。
特别是,对于每个传输进度条显示,如果是下载则为绿色,如果是上传则为红色。
最初我做了一些虚构的尝试,我模拟了传输(网络的线程被停用)。所以这些条形图以编程方式填充,我检查了GUI的性能,一切都很好。特别是我可以选择条形并显示上下文菜单。
经过一段时间,我们开发了基本上做读写TCP的网络部分。对于每个块(或块组),执行“执行步骤”以使条前进。
块的数量因文件而异,但如果有超过100个块,则要执行的步骤数总是100,这样,每次传输总是执行100步或更少。
问题在于,当真正的传输开始时,一切都变慢了,当我四处拖动窗口并且GUI不再响应时,我甚至无法点击条形图来显示上下文菜单。但是,酒吧的进展是有效的。
我们尝试禁用条形图并进行传输,GUI响应迅速,没有任何问题。
我们可能会损害网络的GUI刷新。
网络有自己的线程和另一个GUI。
通过网络刷新条形图的最佳方法是什么?
我们目前正在使用此功能,但我们认为这不是一个好方法,因为它确实效率不高。
例如,我们采用网络客户端代码:
dotnet publish --configuration Release --runtime win-x64
相对于PerformStep()的代码是Transfer共享对象的公共方法:
...
// Object representing a transfer (shared between GUI and Network)
Transfer t = new Transfer(...);
int bytesRead;
var buffer = new byte[chunkSize];
while ((bytesRead = file.Read(buffer, 0, buffer.Length)) > 0)
{
if (t.Stop)
{
break;
}
nwStream.Write(buffer, 0, bytesRead);
PBcount++;
if (PBcount == PBchuks)
{
t.PerformStep(); // Make the progress bar to advance, works, but laggy
PBcount = 0;
}
}
...
以下是委托刷新ListBox项目的MainWindow GUI方法的代码:
public void PerformStep()
{
CurrentStep = CurrentStep + 1;
Application.Current.Dispatcher.Invoke(delegate {
MainWindow wnd = (MainWindow)Application.Current.MainWindow;
wnd?.PerformStepProgressBarRefresh();
});
}
我不知道它是否有用,但无论如何我都会说它,它是与进度条相关的XAML代码:
public void PerformStepProgressBarRefresh()
{
Application.Current.Dispatcher.Invoke(delegate
{
TransfersXAML.Items.Refresh();
});
}
您是否了解更好,更高效的系统,以便网络线程能够以某种方式更新进度条?
毕竟,我们不知道我们是否做得对。
我们可能没有提供可能有助于更好地理解问题的所有信息:发出信号以便我们更新问题。
更新
<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>
答案 0 :(得分:1)
您不需要使用Refresh
或类似技术手动刷新WPF控件。你当然不需要在这里做。
您已将进度条Value
属性正确绑定到Transfer.CurrentStep
,但您没有实施更改通知以自动通知绑定有关更改。为此,您需要在INotifyPropertyChanged
类上实现Transfer
接口,例如:
public class Transfer : INotifyPropertyChanged {
private int _currentStep;
public int CurrentStep
{
get { return _currentStep; }
set
{
if (_currentStep != value) {
_currentStep = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
然后,删除所有PerformStep()
和PerformStepProgressBarRefresh
- 您不再需要它们,也不需要手动执行Dispatcher.Invoke
或BeginInvoke
。在您的网络代码中执行:
t.CurrentStep++;
这就是全部。