gpt4 book ai didi

c# - 报告客户端/服务器环境中的进度

转载 作者:太空宇宙 更新时间:2023-11-03 16:39:09 25 4
gpt4 key购买 nike

在报告长时间运行的服务器操作的进度时,我遇到了一个奇怪的问题。该应用程序具有客户端/服务器架构并用 C# 编写。客户使用 WPF。

在客户端,我创建进度窗口并在后台工作人员中启动一个长时间运行的操作。此操作是通过远程处理调用的服务器方法。作为参数,服务器方法接受用于报告进度的特殊 ProgressContext 对象(请参见下面的代码)。

一旦服务器开始执行一些使用 CPU/内存的繁重操作 - 进度窗口就会卡住。它不响应任何交互,也不更新进度。一段时间后,当繁重的操作完成后 - 进度窗口恢复正常,就像什么也没发生一样。

看起来当我将后台 worker 的实例传递给服务器并且服务器线程负载很重时 - 它与锁定窗口后台 worker 的方式有关。如果我在没有远程调用的情况下使用相同的进度窗口 - 问题就会消失。

为了报告进度,我将进度窗口与 backgroundworker 一起使用,就像网络上的许多示例一样。这是进度窗口的 C# 代码:

public partial class ProgressWindow : Window
{
#region Fields

public static readonly DependencyProperty AutoIncrementProperty =
DependencyProperty.Register(
"AutoIncrement",
typeof(bool),
typeof(ProgressBar),
new UIPropertyMetadata(null));

private readonly BackgroundWorker m_worker;
private CultureInfo m_culture;
private bool m_isCancelled;
private Exception m_error = null;

private Action<IProgressContext> m_workerCallback;

#endregion

#region Constructors

/// <summary>
/// Inits the dialog without displaying it.
/// </summary>
public ProgressWindow()
{
InitializeComponent();

//init background worker
m_worker = new BackgroundWorker();
m_worker.WorkerReportsProgress = true;
m_worker.WorkerSupportsCancellation = true;

m_worker.DoWork += Worker_DoWork;
m_worker.ProgressChanged += Worker_ProgressChanged;
m_worker.RunWorkerCompleted += Worker_RunWorkerCompleted;

AutoIncrement = true;
CancellingEnabled = false;
}

#endregion

#region Public Properties

public bool CancellingEnabled
{
get
{
return btnCancel.IsVisible;
}
set
{
btnCancel.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
}
}

public bool Cancelled
{
get
{
return m_isCancelled;
}
}

public bool AutoIncrement
{
get
{
return (bool)this.GetValue(AutoIncrementProperty);
}
set
{
this.SetValue(AutoIncrementProperty, value);
}
}

public Exception Error
{
get
{
return m_error;
}
}

#endregion

#region Public Methods

public void Run(Action<IProgressContext> action)
{
if (AutoIncrement)
{
progressBar.IsIndeterminate = true;
}

//store the UI culture
m_culture = CultureInfo.CurrentUICulture;

//store reference to callback handler and launch worker thread
m_workerCallback = action;
m_worker.RunWorkerAsync();

//display modal dialog (blocks caller)
ShowDialog();
}

#endregion

#region Private Methods

#region Event Handlers

private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
try
{
//make sure the UI culture is properly set on the worker thread
Thread.CurrentThread.CurrentUICulture = m_culture;

ProgressContext context = new ProgressContext((BackgroundWorker)sender);

//invoke the callback method with the designated argument
m_workerCallback(context);
}
catch (Exception)
{
//disable cancelling and rethrow the exception
Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(SendOrPostCallback)delegate { btnCancel.SetValue(Button.IsEnabledProperty, false); },
null);
throw;
}
}

private void btnCancel_Click(object sender, RoutedEventArgs e)
{
btnCancel.IsEnabled = false;
m_worker.CancelAsync();
m_isCancelled = true;
}

private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage != int.MinValue)
{
progressBar.Value = e.ProgressPercentage;
}

if (e.UserState != null)
{
lblStatus.Text = (string)e.UserState;
}
}

private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
m_error = e.Error;
}

//update UI in case closing the dialog takes a moment
btnCancel.IsEnabled = false;

Close();
}

#endregion

#endregion
}

public class ProgressContext : MarshalByRefObject, IProgressContext
{
#region Fields

private BackgroundWorker m_worker;

#endregion

#region Constructors

public ProgressContext(BackgroundWorker worker)
{
m_worker = worker;
}

#endregion

#region Public Properties

public void ReportProgress(string message)
{
m_worker.ReportProgress(int.MinValue, message);
}

public void ReportProgress(int progress, string message)
{
m_worker.ReportProgress(progress, message);
}

public void ReportProgress(int progress)
{
m_worker.ReportProgress(progress);
}

public bool IsCancelled
{
get
{
return m_worker.CancellationPending;
}
}

#endregion
}

任何帮助将不胜感激。提前致谢。

最佳答案

我怀疑 Backgroundworker 不适合以这种方式使用远程处理进行编码。

将 Backgroundworker 留在客户端,不要传递它并设置一个事件接收器,它是一个 MarshalByRefObject,它保留在客户端并从服务器调用/发出信号。

sink 反过来可以调用 Backgroundworker 上的方法。

关于c# - 报告客户端/服务器环境中的进度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8180138/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com