How to make a file download progress bar in WinForms? - winforms

I'm making a web browser with CefSharp. I just implemented downloads 2 days ago but there is no progress bar to go along with the download. How do I make the progress bar show download progress?

Edit: Making things clearer
Add a ProgressBar Control to your Form and add a BackgroundWorker Component alongside it to your form. Figure out your file size first:
Int64 bytes_total= Convert.ToInt64(client.ResponseHeaders["Content-Length"])
This is code from Alex's amazing answer which can be found here:
public Form1()
{
InitializeComponent();
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
backgroundWorker1.WorkerReportsProgress = true;
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
//Replace this code with a way to figure out how much of the file you have already downloaded and then use backgroundworker1.ReportProgress and send the percentage completion of the file download.
for (int i = 0; i < 100; i++)
{
Thread.Sleep(1000);
backgroundWorker1.ReportProgress(i);
}
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}

Related

Why does WPFMediaKit VideoCaptureElement created by code land ever in MediaFailed?

I add a VideoCaptureElement to a window in runtime but when I run this code it fires MediaFailed. But if I add the same element in XAML then it works fine, I can see the video from the laptop camera.
Am I doing anything wrong? Please help!
public partial class MainWindow : Window
{
WPFMediaKit.DirectShow.Controls.VideoCaptureElement VCE;
public MainWindow()
{
InitializeComponent();
VCE = new WPFMediaKit.DirectShow.Controls.VideoCaptureElement();
Content = VCE;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
VCE.MediaOpened += VCE_MediaOpened;
VCE.MediaFailed += VCE_MediaFailed;
VCE.VideoCaptureDevice = WPFMediaKit.DirectShow.Controls.MultimediaUtil.VideoInputDevices[0]; // This is my laptop webcam
}
void VCE_MediaOpened(Object sender, RoutedEventArgs e) { ... }
void VCE_MediaFailed(object sender, WPFMediaKit.DirectShow.MediaPlayers.MediaFailedEventArgs e) { ... }
}
I had a similar problem with a MediaUriElement working in XAML but not working when instantiated in code-behind.
The solution for me was to Init the control:
VCE.BeginInit();
VCE.EndInit();
This would fit between instantiating (VCE = new...) and assigning (Content = VCE). I haven't tested your particular scenario, but it sounds like the same cause - there must be some extra work done in Init that happens automatically when using XAML.

WPF equivilent of unity 3D's Screen.lockCursor

I haven't used Unity 3D but I gather you can use Screen.lockCursor to take control of the mouse for FPS games. Is this possible in WPF/Win32?
Obviously you have to release it when exiting or in the event of a crash
Thanks
I found the answer spread across a whole bunch of links, so
(1) Set a captureMouse flag, press once to go into this mode, again to come out,
hide the cursor while you are in there
bool captureMouse = false;
private void viewport3D1_MouseDown(object sender, MouseButtonEventArgs e)
{
if (!captureMouse)
{
captureMouse = true;
Mouse.OverrideCursor = Cursors.None;
}
else
{
Mouse.OverrideCursor = null;
captureMouse = false;
}
}
(2) While you're in this mode constantly put the mouse back to the middle of the window
private void theWindow_MouseMove(object sender, MouseEventArgs e)
{
if (!captureMouse)
return;
Point windowPoint = WpfToRealPixels(theWindow, new Point(500, 500));
NativeMethods.SetCursorPos((int)windowPoint.X, (int)windowPoint.Y);
oldP = new Point(500, 500);
}
(3) Translate the co-ords
private Point WpfToRealPixels(Window w, Point p)
{
return theWindow.PointToScreen(p);
}
(4) To put the mouse back you'll need a native Win32 call
public partial class NativeMethods
{
[System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SetCursorPos")]
[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
public static extern bool SetCursorPos(int X, int Y);
}
Hope that helps someone.

How can i run hidef XNA from winforms?

I have winforms application and i have texture SimpleTexture.xnb compiled as HiDef. I need to run XNA 3D visualisation from my winforms application in separate window. I try this:
private void button1_Click(object sender, EventArgs e)
{
System.Threading.Thread thStartGame = new System.Threading.Thread(StartGame);
thStartGame.Start();
}
private void StartGame()
{
using (Game1 game = new Game1())
{
game.Run();
}
}
But i get error:
Error loading "SimpleTexture". This file was compiled for the HiDef profile, and cannot be loaded into a Reach GraphicsDevice.
What can i do to run this??
Change reach to hidef:
YourGraphicsDeviceManager.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs (graphics_PreparingDeviceSettings);
void graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
{
e.GraphicsDeviceInformation.GraphicsProfile = GraphicsProfile.HiDef;
}

Update GUI using BackgroundWorker

I've been searching and found that a good way to perform background work and update the GUI is using background workers. However, doing this (stupid) little task (counting from 1 to 10000) it doesn't update the label content but prints to the debug! (This is just a spike solution for another project of course...)
Here's the code:
public partial class MainWindow : Window
{
BackgroundWorker bw = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.WorkerReportsProgress = true;
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("DONE");
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Content = "going here: "+e.ProgressPercentage;
Debug.WriteLine(e.ProgressPercentage);
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i=0; i < 10000; i++)
{
bw.ReportProgress((i*100)/10000);
}
}
}
The ProgressChanged event is raised on the UI thread, not the worker thread. In your code, the worker thread is doing almost nothing (just loop from 0 to 10000 and call ReportProgress), most of the work is done on the UI thread. Basically, you're sending too many progress notifications. Because of this, the UI thread is almost always busy and has no time to render the new content of the label.
Rendering in WPF is not performed immediately when you change a property of a control, it is done on a separate dispatcher frame, which is processed when the dispatcher has nothing more urgent to do, based on the priority of the task. The priority used for rendering has a value of 7 (DispatcherPriority.Render); the ProgressChanged event is marshalled to the UI thread with a priority of 9 (DispatcherPriority.Normal), as specified on MSDN. So the ProgressChanged notifications always have a higher priority than rendering, and since they keep coming, the dispatcher never has time to process the rendering tasks.
If you just decrease the frequency of the notifications, your app should work fine (currently you're sending 100 notifications for each percentage value, which is useless):
void bw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 10000; i++)
{
if (i % 100 == 0)
bw.ReportProgress(i / 100);
}
}
this.Dispatcher.BeginInvoke( (Action) delegate(){
label1.Content = "going here: "+e.ProgressPercentage;
});
Try to change the label using womething like this:
string Text = "going here: " + e.ProgressPercentage;
this.Invoke((MethodInvoker)delegate {
label1.Content = newText;
});
Note that i'm not sure it will work. I can not test it now. If it does not work, let me know and I will delete the answer.
If you need the a canonical way to do exactly what you want, look at the Hath answer in this post: How do I update the GUI from another thread?

Stream a WAV File From The Web In Silverlight 3

I've managed to discover Gilles Khouzam's playback implementation for WAV files in Silverlight 3 and while that would be the majority of the battle, I'm stuck on a final detail: how do I pull a wav file from the web some place and then feed it into his WaveMediaStreamSource for playback?
Here's the closest I've come:
public MainControl()
{
// Required to initialize variables
InitializeComponent();
PlayButton.Click += PlayButtonClicked;
}
private void PlayButtonClicked(object sender, RoutedEventArgs e)
{
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(#"soundfile.wav");
request.BeginGetResponse(ReadCallback, request);
}
private void ReadCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
WaveMediaStreamSource wavMss = new WaveMediaStreamSource(response.GetResponseStream());
MediaPlayer.SetSource(wavMss);
}
Edit:
It turns out the problem had to do with HttpWebRequest. Changing the code to:
public MainPage()
{
InitializeComponent();
WebClient webClient = new WebClient();
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(new Uri(#"http://www.russellmyers.com/somefile.wav", UriKind.Absolute));
}
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
WaveMediaStreamSource wavMss = new WaveMediaStreamSource(e.Result);
Debug.WriteLine("Setting source...");
Media.SetSource(wavMss);
}
Works fine. This makes sense too after reading Shawn Wildermuth's article on the differences. I would like to get HttpWebRequest working though because it won't be done on the UI thread.

Resources