I'm getting this exception
The process cannot access the file 'myfile.zip' because it is being used by another process.
When I try to delete a file. I understand the error, but I'm not sure what other process could be using the file.
I'm downloading the file via WebClient asynchronously, but I cancel the download before trying to delete it, which means that process should relinquish it, no?
Here are the relevant methods. It's a simple file-downloader:
private void textBox1_KeyUp(object sender, KeyEventArgs e)
{
string downloadFile = textBox1.Text.Trim();
if (e.Key == Key.Return && downloadFile != "")
{
var dlg = new SaveFileDialog();
dlg.FileName = Path.GetFileName(downloadFile);
dlg.DefaultExt = Path.GetExtension(downloadFile);
var result = dlg.ShowDialog();
if(result.Value)
{
textBox1.Text = "";
textBox1.Focus();
_saveFile = dlg.FileName;
progressBar1.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => progressBar1.Foreground = new SolidColorBrush(Color.FromRgb(0, 255, 0))));
_webClient.DownloadFileAsync(new Uri(downloadFile), _saveFile);
}
}
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (_webClient.IsBusy && _saveFile != null)
{
var result = MessageBox.Show("Download in progress. Are you sure you want to exit?", "Exit?", MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result == MessageBoxResult.Yes)
{
_webClient.CancelAsync();
File.Delete(_saveFile);
}
else
{
e.Cancel = true;
}
}
}
You need to wait when downloading realy canceled. When call _webClient.CancelAsync(); next operator executes immediatley before webClient canceled.
May be you need delete the file in callback of CancelAsync(...)
Related
I have a button on my WinForm. Code works great until I observed my test users.
They don't wait for the PDF to launch. Instead they will click it several times (causing multiple instances of the Acrobat reader to launch
private void pictureBoxNewsLetter_Click(object sender, EventArgs e)
{
lockControls();
launchNewsLetter();
unlockControls();
}
private void launchNewsLetter()
{
// Newsletter
lockControls();
ProcessStartInfo psi = new ProcessStartInfo(#"Y:\Newsletter.pdf");
Process ps = new Process { StartInfo = psi };
ps.Start();
ps.WaitForExit();
Thread.Sleep(1000);
unlockControls();
}
--- Code to disable my controls.
private void lockControls()
{
dontRunHandler = false;
foreach (var pb in this.Controls.OfType<PictureBox>())
{
pb.Enabled = false;
}
}
private void unlockControls()
{
dontRunHandler = true;
foreach (var pb in this.Controls.OfType<PictureBox>())
{
pb.Enabled = true;
}
}
This is my service which checks username and password
[OperationContract]
public bool LoginCheck(string username, string password)
{
RoadTransDataContext db = new RoadTransDataContext();
var _Pass = (from d in db.users where d.username == username select d.password).SingleOrDefault();
if (_Pass == password)
{
return true;
}
else
{
return false;
}
}
And this is child window
private void LoginCheckCompleted(object sender, ServiceReference.LoginCheckCompletedEventArgs e)
{
_Log = e.Result;
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
ServiceReference.ServiceClient webservice = new ServiceReference.ServiceClient();
webservice.LoginCheckCompleted += new EventHandler<ServiceReference.LoginCheckCompletedEventArgs>(LoginCheckCompleted);
webservice.LoginCheckAsync(txtUserName.Text, txtPassword.Password);
if (_Log == true)
{
this.DialogResult = true;
this.Close();
}
}
problem is that LoginCheckCompleted method is calling when OKButton_Click method finished. so if it input correct username, pass and press button it doing nothing if i click onece again window closing
Silverlight uses the async model of invoking web services and it takes some time to wait until the response is returned. In your example the assigment _Log = e.Result; will be called, let's assume, after 1-2 seconds, whereas the check if (_Log == true) will be called immideately and of course before the assignment.
That's why you should put all the necessary code in the callback and remove all the code after the async call. I've fixed it for you:
private void LoginCheckCompleted(object sender, ServiceReference.LoginCheckCompletedEventArgs e)
{
_Log = e.Result;
if (_Log == true)
{
this.DialogResult = true;
this.Close();
}
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
ServiceReference.ServiceClient webservice = new ServiceReference.ServiceClient();
webservice.LoginCheckCompleted += new EventHandler<ServiceReference.LoginCheckCompletedEventArgs>(LoginCheckCompleted);
webservice.LoginCheckAsync(txtUserName.Text, txtPassword.Password);
}
I am downloading data after every 5mins using web client but sometimes it shows a concurrency error.
TimerCallback call = down;
temp = new Timer(call);
temp.Change(1000, System.Threading.Timeout.Infinite);
public void down(object obj)
{
if(webflag == true)
webClient.DownloadStringAsync(new Uri(url));
webflag = false;
}
private void FeedsDownloaded(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
// some processing
}
webflag = true;
temp.Change(5000, System.Threading.Timeout.Infinite);
}
I am beginner so the above code must look pretty messed up. Appreciate guidance, Thanks!
Thank You Drew Marsh, The solution was using webClient.isbusy flag.
if(webClient.isbusy == false)
webClient.DownloadStringAsync(new Uri(url));
I have a MVP like application, all expensive operations are using Async calls and display an Ajax like gif that indicates the user that something is happening without blocking the main thread.
Example:
Data entry form, user clicks Save, an async operation takes place and when it finishes restores the screen to an editable form without blocking the UI thread (in other terms, not blocking other visible windows in the application).
Everything works fine in here, but given the following scenario:
User tries to close the Form, and gets a confirmation message that asks the user if he is sure that he is going to close if he prefers to Save before closing.
When the users clicks 'Save' the same logic explained before takes place, but I'm forced to wait for this call to finish in the UI thread (in case there are any errors in the async call or whatever) and I can`t find any way of doing it other way without blocking the UI thread.
Any suggestions? Thanks!
--- Edit ----
What I'm doing right now is waiting on all my WaitHandles in the Presenter with this loop:
while (!WaitHandles.All(h => h.WaitOne(1)))
Application.DoEvents();
It feels a little dirty.. but at least it simulates non blocking the thread. Is this something that for some reason I should not be doing?
Here is an example of the "hide method". Granted, it's not MVP, it's just an example.
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
class Form1 : Form
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
public Form1()
{
Text = "First Form";
Button button;
Controls.Add(button = new Button { Text = "Launch 2nd Form", AutoSize = true, Location = new Point(10, 10) });
button.Click += (s, e) => new Form2 { StartPosition = FormStartPosition.Manual, Location = new Point(Right, Top) }.Show(this);
}
}
class Form2 : Form
{
public Form2()
{
Text = "Second Form";
dirty = true;
}
private bool dirty;
protected override void OnClosing(CancelEventArgs e)
{
DialogResult result;
if (dirty && (result = new ConfirmSaveForm().ShowDialog(this)) != DialogResult.No)
{
if (Owner != null)
Owner.Activate();
Hide();
e.Cancel = true;
SaveAsync(result == DialogResult.Cancel);
}
base.OnClosing(e);
}
protected override void OnClosed(EventArgs e)
{
Trace.WriteLine("Second Form Closed");
base.OnClosed(e);
}
private void SaveAsync(bool fail)
{
SaveAsyncBegin();
var sad = new Action<bool>(PerformAsyncSave);
sad.BeginInvoke(fail, (ar) =>
{
try { sad.EndInvoke(ar); }
catch (Exception ex) { Invoke(new Action<Exception>(SaveAsyncException), ex); return; }
Invoke(new Action(SaveAsyncEnd));
}, null);
}
private void SaveAsyncBegin()
{
// Update UI for save
}
private void PerformAsyncSave(bool fail)
{
Trace.WriteLine("Begin Saving");
Thread.Sleep(1000); // Do some work
if (fail)
{
Trace.WriteLine("Failing Save");
throw new Exception("Save Failed");
}
dirty = false;
}
private void SaveAsyncEnd()
{
Trace.WriteLine("Save Succeeded");
Close();
}
private void SaveAsyncException(Exception ex)
{
Trace.WriteLine("Save Failed");
Show();
MessageBox.Show(this, ex.Message, "Save Failed", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
}
class ConfirmSaveForm : Form
{
public ConfirmSaveForm()
{
Text = "Confirm Save";
FormBorderStyle = FormBorderStyle.FixedDialog;
ControlBox = false;
ClientSize = new Size(480, 50);
StartPosition = FormStartPosition.CenterParent;
Controls.Add(new Button { Text = "Yes, Fail", DialogResult = DialogResult.Cancel, Size = new Size(150, 30), Location = new Point(10, 10) });
Controls.Add(new Button { Text = "Yes, Succeed", DialogResult = DialogResult.Yes, Size = new Size(150, 30), Location = new Point(160, 10) });
Controls.Add(new Button { Text = "No", DialogResult = DialogResult.No, Size = new Size(150, 30), Location = new Point(320, 10) });
AcceptButton = Controls[0] as IButtonControl;
}
}
Greetings,
I want to write code that executes within an event handler, inside a WPF Windows application, that can detect a keypress, specifically an "Escape" character keypress, within a processing loop. This will allow the user to escape from processing. I realize this may be accomplished with some kind of multi-threaded approach, but the problem seems so simple I wondered if it might be accomplished as follows:
// Attempt 1: See if Keyboard static IsKeyDown method detects key presses while executing.
// Note that this was not successful. The Keyboard states do not appear to be updated during processing.
bool iskeypressed = false;
while (!iskeypressed)
{
System.Threading.Thread.Sleep(1000);
if (Keyboard.IsKeyDown(Key.Enter))
iskeypressed = true;
}
So, on to attempt #2. I saw some articles and samples using the Pinvoke "GetKeyboardState" method. I'm not sure I used the method correctly, but here is my attempt. It is a bit clumsy to refer to a Windows.Forms enumeration in a WPF application, but it seems like it could work.
// Attempt 2: Use Pinvoke GetKeyboardState method.
// So far, I've been unsuccessful with this as well, but I'm not sure my usage is correct.
bool iskeypressed = false;
while (!iskeypressed)
{
System.Threading.Thread.Sleep(1000);
if (isEscapePressed())
iskeypressed = true;
}
}
[DllImport("user32.dll")] public static extern int GetKeyboardState(byte[] lpKeyState);
private bool isEscapePressed()
{
byte[] keyboardState = new byte[255];
int keystate = GetKeyboardState(keyboardState);
if (keyboardState[(int)System.Windows.Forms.Keys.Escape] == 128)
return true;
else
return false;
}
But unfortunately, I'm not seeing any change in the keyboard states as this executes. I also played around a little with calls to the Dispatcher to see if I could get the keyboard information to refresh during processing, but I have not been successful with any technique.
I'm out of ideas. Can someone propose something? Thank you in advance for your assistance.
David
Something like this:
private bool IsCancelled { get; set; }
private void OnButtonClick(object sender, EventArgs e)
{
Action doWorkDelegate = DoWork;
doWorkDelegate.BeginInvoke(null, null);
}
protected override void OnKeyDown(KeyEventArgs e) {
if (e.Key == Key.Escape) {
IsCancelled = true;
e.Handled = true;
} else {
base.OnKeyDown(e);
}
}
private void DoWork()
{
IsCancelled = false;
while (!IsCancelled)
{
System.Threading.Thread.Sleep(1000);
}
}
The important point is that the method that does the work is executed in a separate thread so the main thread can process user input (key strokes).
You can not detect a key event while you are blocking WPF by executing a very long loop. You must use a multithreaded approach or you have to split the loop.
Using a BackgroundWorker is an easy way to let WPF continue handling the frontend while executing the loop.
private BackgroundWorker bw;
private void Button_Click(object sender, RoutedEventArgs e)
{
if (bw != null)
return;
bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.WorkerReportsProgress = true;
bw.DoWork += (senderBw, eBw) =>
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(1000);
bw.ReportProgress(i);
if (eBw.Cancel)
return;
}
};
bw.ProgressChanged += (senderBw, eBw) =>
{
//TODO set progressbar to eBw.ProgressPercentage
};
bw.RunWorkerCompleted += (senderBw, eBw) =>
{
this.bw = null;
//TODO frontend stuff (hide progressbar etc)
};
bw.RunWorkerAsync();
}
private void MainWindow_KeyDown(object sender, KeyEventArgs e)
{
if (this.bw != null && this.bw.IsBusy && e.Key == Key.Escape)
this.bw.CancelAsync();
}