Per a client's request I have written a communication class that inherits from webclient. They want to be able to "Pass in a custom windows form as a progress bar" rather than that I created an interface that implements 3 properties. Anyway the problem I am having is the app starts and i click the start button so to speak and the first time i do this the ui thread is frozen, after a few seconds it unfreezes and the progress bar and data begin coming down.
After this initial freeze though , any subsequent presses of the start button work perfectly and do not block the thread any ideas?
Here are the relevant pieces of code from form 1
private void btnSubmit_Click(object sender, EventArgs e)
{
txtResponse.Text = "";
progressForm = new ProgressFormTest();
myCommunication = new CommunicationClient(progressForm);
myCommunication.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_RequestComplete);
// myCommunication.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
myCommunication.Timeout += new EventHandler(wc_TimeOut);
myCommunication.Cancelled += new EventHandler(myCommunication_Cancelled);
progressForm.Show();
myCommunication.TimeoutValue = (int)numConnectionTimeout.Value * 1000;
myCommunication.DownloadStringAsync(new Uri(txtUrl.Text));
}
Here is the communication class
public class CommunicationClient:WebClient
{
private int step = 1000;
private long bytesReceived;
private long bytesSent;
private Status status;
private System.Timers.Timer _timer;
private IProgress myProgressForm;
/// <summary>
/// Sets the timeout value in milliseconds
/// </summary>
public int TimeoutValue { get; set; }
public int TimeElapsed { get; set; }
public long BytesReceived
{
get
{
return bytesReceived;
}
}
public long BytesSent
{
get
{
return bytesSent;
}
}
public event EventHandler Timeout;
public event EventHandler Cancelled;
public CommunicationClient(IProgress progressForm)
{
myProgressForm = progressForm;
_timer = new System.Timers.Timer(step);
_timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
}
protected override void OnDownloadStringCompleted(DownloadStringCompletedEventArgs e)
{
_timer.Stop();
if (status == Status.Completed)
{
myProgressForm.PercentComplete = 100;
base.OnDownloadStringCompleted(e);
}
}
protected override void OnDownloadProgressChanged(DownloadProgressChangedEventArgs e)
{
bytesReceived = e.BytesReceived;
myProgressForm.BytesReceived = bytesReceived;
if (e.TotalBytesToReceive == -1)
myProgressForm.PercentComplete = calculateFakePercentage();
else
myProgressForm.PercentComplete = e.ProgressPercentage;
base.OnDownloadProgressChanged(e);
}
protected virtual void OnTimeout(EventArgs e)
{
if (Timeout != null)
{
CancelAsync();
this.Dispose();
Timeout(this, e);
}
}
protected virtual void OnCancelled(EventArgs e)
{
if (Cancelled != null)
{
this.Dispose();
Cancelled(this, e);
}
}
/// <summary>
/// Cancels a pending asynchronous operation and raises the Cancelled Event
/// </summary>
/// <param name="Event">Set to true to raise the event</param>
public void CancelAsync(bool Event)
{
CancelAsync();
if (Event)
{
status = Status.Cancelled;
OnCancelled(new EventArgs());
}
}
private void initialize()
{
status = Status.Completed;
TimeElapsed = 0;
_timer.Start();
}
new public void DownloadStringAsync(Uri url)
{
initialize();
base.DownloadStringAsync(url);
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
TimeElapsed += step;
if (TimeElapsed >= TimeoutValue)
{
_timer.Stop();
status = Status.Timeout;
OnTimeout(e);
}
}
//used when the website in question doesnt provide the content length
private int calculateFakePercentage()
{
return (int)bytesReceived * 100 / 60000 ;
}
}
And here is the simple Interface IProgressForm
public interface IProgress
{
int PercentComplete
{
get;
set;
}
long BytesReceived
{
get;
set;
}
long BytesSent
{
get;
set;
}
}
Fixed it , I set the Proxy property from the webclient class to null and that seemed to fix it
Related
Here is my code for refrence
public class ProgressChangedObject
{
public string Asin { get; set; }
public string Title { get; set; }
public DownloadProgress downloadProgress { get; set; }
public ProgressChangedObject(string asin, string title, DownloadProgress progress)
{
Asin = asin;
Title = title;
downloadProgress = progress;
}
}
public record QueueFile(string asin, string name);
public class BlockingCollectionQueue : IDownloadQueue
{
private BlockingCollection<QueueFile> _jobs = new BlockingCollection<QueueFile>();
public volatile List<QueueFile> queueFiles = new List<QueueFile>();
private readonly AudibleApi.Api _api;
private readonly LibraryPath _libraryPath;
private volatile float percentComplete;
private volatile QueueFile? currentJob;
private System.Timers.Timer _timer;
public BlockingCollectionQueue(AudibleApi.Api api, LibraryPath libraryPath)
{
var thread = new Thread(new ThreadStart(OnStart));
thread.IsBackground = true;
thread.Start();
_api = api;
_libraryPath = libraryPath;
_timer = new System.Timers.Timer(500);
_timer.Elapsed += TimerTick;
}
~BlockingCollectionQueue()
{
_timer.Dispose();
}
private void TimerTick(object? sender, System.Timers.ElapsedEventArgs e)
{
if (currentJob != null)
{
ProgressChanged?.Invoke(new ProgressChangedObject(currentJob.asin, currentJob.name, new DownloadProgress() { ProgressPercentage = percentComplete }));
}
}
public event Action<ProgressChangedObject>? ProgressChanged;
public void Enqueue(QueueFile job)
{
_jobs.Add(job);
queueFiles.Add(job);
}
private async void OnStart()
{
foreach (var job in _jobs.GetConsumingEnumerable(CancellationToken.None))
{
_timer.Enabled = true;
var d = new Progress<DownloadProgress>();
EventHandler<DownloadProgress> del = (object? sender, DownloadProgress e) => { if (e.ProgressPercentage is not null) { percentComplete = (float)e.ProgressPercentage; currentJob = job; } };
d.ProgressChanged += del;
await _api.DownloadAsync(job.asin, _libraryPath, new AsinTitlePair(job.asin, job.name), d);
d.ProgressChanged -= del;
_timer.Enabled = false;
queueFiles.Remove(job);
}
}
public List<QueueFile> GetQueue()
{
//MessageBox.Show(_jobs.GetConsumingEnumerable().Count().ToString());
return queueFiles;
}
}
I have an instance of this class in my app and when I need to download something I simply add a new queuefile to the queue, the problem is when I subscribe to the Progress changed event like this :
IDownloadQueue downloadQueue = new BlockingCollectionQueue();
downloadQueue.ProgressChanged += OnQueueChanged;
private void OnQueueChanged(ProgressChangedObject obj)
{
\\ some textblock in my xaml
myTextBlock.Text = obj.Title;
}
It throws this error:
Exception thrown: 'System.InvalidOperationException' in WindowsBase.dll
An exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll but was not handled in user code
The calling thread cannot access this object because a different thread owns it.
How can I fix this?
You should use Dispatcher.Invoke Method
You cannot access the GUI thread from a background thread. However, you can use as per below:
Dispatcher.BeginInvoke(new Action(() =>
{
// FooProgressBar.Value = ProgressData();
}));
For more information visit Threading Model
Please go through the following code which is an oversimplification of the code I have.
I need to know how once the timer is elapsed, how to return control to the main user control class, preferably to the same case within the switch statement.
public partial class ucClass : UserControl
{
int A;
Label labelTimer = new Label();
sec secObj = new sec();
public execute()
{
switch(A)
{
case 1:
secObj.initiate(labelTimer, 10);
break:
case 2:
......
}
}
}
class sec
{
public System.Windows.Forms.Timer timer;
private Label labelTimer = new Label();
private int expectedCount = 0;
private int actualCount = 0;
public void initiate(Label labelTimer, int count)
{
this.expectedCount = count;
this.labelTimer = labelTimer;
this.timer.Interval = 1000;
startTimer();
}
private void startTimer()
{
this.timer.Start();
this.timer.Tick += this.timerElapsed;
}
private void timerElapsed(object sender, EventArgs e)
{
this.timer.Dispose();
if(expectedCount > actualCount)
{
this.actualCount += 1;
this.labelTimer.Text = this.actualCount.ToString();
this.startTimer();
}
else
{
//this is where I need to notify the main class that timer has expired and go to case 2
}
}
}
You can achieve the behavior that you want with events:
public partial class ucClass : UserControl
{
int A;
Label labelTimer = new Label();
sec secObj = new sec();
public ucClass()
{
// Listen to event from timer
secObj.TimerExpired += (sender, args) =>
{
A = args.Count;
execute();
};
}
public void execute()
{
switch(A)
{
case 1:
secObj.initiate(labelTimer, 10);
break:
case 2:
......
}
}
}
class sec
{
public System.Windows.Forms.Timer timer;
public event EventHandler<TimerExpiredEventArgs> TimerExpired;
private Label labelTimer = new Label();
private int expectedCount = 0;
private int actualCount = 0;
public void initiate(Label labelTimer, int count)
{
this.expectedCount = count;
this.labelTimer = labelTimer;
this.timer.Interval = 1000;
startTimer();
}
private void startTimer()
{
this.timer.Start();
this.timer.Tick += this.timerElapsed;
}
private void timerElapsed(object sender, EventArgs e)
{
this.timer.Dispose();
if(expectedCount > actualCount)
{
this.actualCount += 1;
this.labelTimer.Text = this.actualCount.ToString();
this.startTimer();
}
else
{
// Send event with count
TimerExpired?.Invoke(this, new TimerExpiredEventArgs
{
Count = actualCount
});
}
}
}
public class TimerExpiredEventArgs
{
public int Count { get; set; }
}
I would recommend looking into the following;
The MVVM pattern
This will allow you to seperate the UI logic (passing around labels etc) and the control logic (timers etc).
Reactive Extensions (https://github.com/dotnet/reactive)
This would allow for a very simple timer:
Observable
.Interval(TimeSpan.FromSeconds(1))
.Subscribe(count => {
labelTimer.Text = count.ToString();
if (count > actualCount) {
A = args.Count;
execute();
}
});
I want to test whether my event has to be raised or not using unit testing. In my project, I passed a progress value from one class to another using event handler. I working on MVVM method so, I passed the value from Model class to ViewModel class. How to write unit test for the event handler.
I try to write unit test for the event handlers called GetTotalFileSize and TransferredFileSize.But i could not raise the events on test. So, What I have to do?
[Test]
public void IsGetTotalFileSizeEventFired()
{
worflowManager = new Mock<IWorkflowManager>().Object;
ripWatcherWindowShellViewModel =
new RipWatcherWindowShellViewModel(worflowManager);
ripWatcherWindowShellViewModel.GetTotalFileSize
+= delegate { eventRaised = true; };
Assert.IsTrue(eventRaised);
}
//production code is..
public RipWatcherWindowShellViewModel(IWorkflowManager workflowManager)
{
WorkflowManager = workflowManager;
workflowManager.TransferredUsfFileSizeChanged
+= workflowManager_TransferredUsfFileSizeChanged;
workflowManager.GetTotalUsfFileSize
+= workflowManager_GetTotalFileSize;
}
public void workflowManager_GetTotalFileSize(object sender, FileSizeChangedEventArgs e)
{
if(e.FileSize== 0)
{
throw new ArgumentException("We cannot calculate progress percentage because total file size is 0");
}
TotalUsfFileSize = e.FileSize;
}
public void workflowManager_TransferredUsfFileSizeChanged(object sender, FileSizeChangedEventArgs e)
{
if(e.FileSize !=0)
{
TransferredUsfFileSize = e.FileSize;
}
else
{
tempFileSize += TransferredUsfFileSize;
}
/*Calculating progress percentage for updating progress bar*/
ProgressPercentage = (int)(((TotalUsfFileSize -(TotalUsfFileSize-(tempFileSize+TransferredUsfFileSize)))/TotalUsfFileSize)* 100);
}
public Double TransferredUsfFileSize
{
get;
set;
}
/// <summary>Gets or sets the total file size</summary>
public Double TotalUsfFileSize
{
get;
set;
}
public IWorkflowManager WorkflowManager { get; set; }
public int ProgressPercentage
{
get
{
return percentage;
}
set
{
percentage = value;
OnPropertyChanged("ProgressPercentage");
}
}
The value came from..
public void CopyEx(string sourceFilePath,string destinationFilePath)
{
try
{
lock (locker)
{
CopyFileEx(sourceFilePath, destinationFilePath,
new CopyProgressRoutine(this.CopyProgressHandler),
IntPtr.Zero, ref pbCancel,
CopyFileFlags.COPY_FILE_RESTARTABLE);
}
}
catch(Exception ex)
{
throw new Exception(ex.message);
}
}
private CopyProgressResult CopyProgressHandler(long total,
long transferredFileSize, long streamSize,
long StreamByteTrans, uint dwStreamNumber,
CopyProgressCallbackReason reason,
IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData)
{
TransferredUsfFileSizeChanged.SafeInvoke(this,
new FileSizeChangedEventArgs(transferredFileSize));
return CopyProgressResult.PROGRESS_CONTINUE;
}
public EventHandler<FileSizeChangedEventArgs>
TransferredUsfFileSizeChanged;
I'm creating an Windowns phone 8 app(c#), its a countdown interval timer, so there is prepare time(10 sec), work time(20 sec), rest time(10 sec). I have these variables
`TimeSpan prepInterval = new TimeSpan(0, 0, 0, 10);
TimeSpan workInterval = new TimeSpan(0, 0, 0, 20);
TimeSpan restInterval = new TimeSpan(0, 0, 0, 10);`
I can't wrap my head around having them implementing them one after another when they hit 0. So when prepare time is done, the work timer is to start and when thats finised, the rest timer is to start.
If you would like to have some more broken down logic in all of this, maybe you can create some classes based on a simple interface, like the following:
interface ITimerAction
{
int Seconds { get; set; }
bool Started { get; }
bool Completed { get; }
void OnStart();
void OnComplete();
}
interface ITimerActionList
{
void Add(ITimerAction action);
void Work();
event EventHandler OnCompletedEvent;
}
This would then allow you to create an abstract TimerAction class, and TimerActionList
abstract class TimerAction : ITimerAction
{
public virtual int Seconds
{
get;
set;
}
public virtual bool Completed
{
get;
protected set;
}
public virtual bool Started
{
get;
protected set;
}
public abstract void OnStart();
public abstract void OnComplete();
}
class TimerActionList : ITimerActionList
{
public event EventHandler OnCompletedEvent;
private readonly IList<ITimerAction> actions = new List<ITimerAction>();
private bool working = false;
private Thread myThread;
public void Add(ITimerAction action)
{
if (working)
{
throw new InvalidOperationException("Cannot add new timers when work is already in progress");
}
actions.Add(action);
}
protected virtual void DoWork()
{
working = true;
int currentStep = 0, maxSteps = actions.Count;
while (currentStep < maxSteps)
{
ITimerAction action = actions[currentStep];
if (!action.Started)
{
action.OnStart();
}
if (action.Completed)
{
currentStep++;
continue;
}
if (action.Seconds == 0)
{
action.OnComplete();
continue;
}
action.Seconds--;
Thread.Sleep(1000);
}
Completed();
}
public void Work()
{
if (working)
{
throw new InvalidOperationException("Already running!");
}
working = true;
myThread = new Thread(DoWork);
myThread.Start();
}
protected virtual void Completed()
{
myThread = null;
working = false;
actions.Clear();
var local = OnCompletedEvent;
if (local != null)
{
local.Invoke(this, EventArgs.Empty);
}
}
}
You could then write the classes that inherit from the TimerAction class, that could handle an action before and after the timer ran through :)
class PrepareTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Preparing");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Prepare ready");
Completed = true;
}
}
class WorkTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Working");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Work ready");
Completed = true;
}
}
class CoolDownTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Cooling down");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Cooldown ready");
Completed = true;
}
}
And then you could test the code as such
static void Main(string[] args)
{
bool done = false;
ITimerActionList mylist = new TimerActionList();
mylist.Add(new PrepareTimer { Seconds = 1 });
mylist.Add(new WorkTimer { Seconds = 2 });
mylist.Add(new CoolDownTimer { Seconds = 1 });
mylist.OnCompletedEvent += (sender, e) =>
{
done = true;
};
mylist.Work();
while (!done)
{
// timer is running
}
Console.WriteLine("Done!");
}
(Console program, but i guess that also goes to demonstrate?)
Here's an example based on deathismyfriend's and Hans Passant's suggestions:
var start = new DateTime();
var stage = 0;
var timer = new System.Timers.Timer(100);
timer.Elapsed += (s, e) =>
{
var elapsed = DateTime.Now - start;
int duration = stage == 1 ? 20 : 10;
if (elapsed.TotalSeconds > duration)
{
start = DateTime.Now;
stage++;
if (stage > 2)
timer.Stop();
}
};
start = DateTime.Now;
stage = 0;
timer.Start();
I'm totally new to Events and delegates in C#.
I want to handle a data read event in one class (ex. program) and port reading is done in another class(ex. transfer).
I know how to do it with delegates alone,but don't know how to do it in events.
Could you give me a simple sample. Thanks.
look at this example
public class TimerManager : INotifyPropertyChanged
{
private readonly DispatcherTimer dispatcherTimer;
private TimeSpan durationTimeSpan;
private string durationTime = "00:00:00";
private DateTime startTime;
private bool isStopped = true;
readonly TimeSpan timeInterval = new TimeSpan(0, 0, 1);
public event EventHandler Stopped;
public TimerManager()
{
durationTimeSpan = new TimeSpan(0, 0, 0);
durationTime = durationTimeSpan.ToString();
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += DispatcherTimerTick;
dispatcherTimer.Interval = timeInterval;
dispatcherTimer.IsEnabled = false;
DefaultStopTime = new TimeSpan(17, 30, 0);
}
public TimerManager(TimeSpan defaultStopTime)
: this()
{
DefaultStopTime = defaultStopTime;
}
#region Properties
public TimeSpan ElapsedTime
{
get { return durationTimeSpan; }
}
public string DurationTime
{
get { return durationTime; }
set
{
durationTime = value;
OnPropertyChanged("DurationTime");
}
}
public DateTime StartTime
{
get { return startTime; }
}
public bool IsTimerStopped
{
get
{
return isStopped;
}
set
{
isStopped = value;
OnPropertyChanged("IsTimerStopped");
}
}
public TimeSpan DefaultStopTime { get; set; }
#endregion
#region Start Stop Timer
public void StartTimer()
{
dispatcherTimer.Start();
durationTimeSpan = new TimeSpan(0,0,0);
startTime = DateTime.Now;
IsTimerStopped = false;
}
public void StopTimer()
{
dispatcherTimer.Stop();
IsTimerStopped = true;
if (Stopped != null)
{
Stopped(this, new EventArgs());
}
}
#endregion
public void DispatcherTimerTick(object sender, EventArgs e)
{
// durationTimeSpan = DateTime.Now - startTime;
durationTimeSpan = durationTimeSpan.Add(timeInterval);
DurationTime = string.Format("{0:d2}:{1:d2}:{2:d2}", durationTimeSpan.Hours, durationTimeSpan.Minutes,
durationTimeSpan.Seconds);
if (DateTime.Now.TimeOfDay >= DefaultStopTime)
{
StopTimer();
}
}
}
in this class we have the Timer Stopped event
public event EventHandler Stopped;
in the Method we call the event handler if it is not null
public void StopTimer()
{
dispatcherTimer.Stop();
IsTimerStopped = true;
if (Stopped != null)
{
//call event handler
Stopped(this, new EventArgs());
}
}
for use this class and timer stop event look at the code
var timer = new TimerManager();
timer.Stopped += TimerStopped;
void TimerStopped(object sender, EventArgs e)
{
// do you code
}
If I nright understood what you're asking for, you can do something like this:
public class MyClass
{
...
public void delegate MuCustomeEventDelegate( ...params...);
public event MuCustomeEventDelegate MuCustomeEvent;
...
}