I have a webBrowser on my UI. I ask if it is possible that it is not displayed directly but instead through an image, and I want that the image is updated only when the LoadCompleted event is received.
How to do?
I'm not sure if I understood your question, but if I did, you basically want to show the loaded web page only when its rendering has finished.
If so, this code should do the trick (I'm assuming you hooked the "LoadCompleted" event up to the "webBrowser1_LoadCompleted" method). This code uses a Button ("button1") to trigger the navigation, but you can use it in any other place.
//here is the code that triggers the navigation: when the button is clicked, I hide the
//webBrowser and then navigate to the page (here I used Google as an example)
private void button1_Click(object sender, RoutedEventArgs e)
{
webBrowser1.Visibility = Visibility.Hidden;
webBrowser1.Navigate(new Uri("http://www.google.it"));
}
private void webBrowser1_LoadCompleted(object sender, NavigationEventArgs e)
{
webBrowser1.Visibility = Visibility.Visible;
}
Keep in mind, though, that not showing anything to the user for a long period of time (as with a heavy page) is not always a good idea, depending on the kind of application you're writing. This is up to you, though.
(I decided to leave the previous answer if someone needs it)
If you want to leave the previous page visible until the new one appears, then I think you need a Windows DLL. This is how I would do it.
At the top of the code file, insert these two import statements:
using System.Runtime.InteropServices;
using System.Windows.Interop;
Then you need to declare your DLL function like this (in the Window class):
[DllImport("user32")]
private static extern int LockWindowUpdate (IntPtr hWnd);
Then, let's modify the code in the previous answer a little bit:
private void button1_Click(object sender, RoutedEventArgs e)
{
IntPtr handle = new WindowInteropHelper(Application.Current.MainWindow).Handle;
LockWindowUpdate(handle);
webBrowser1.Navigate(new Uri("http://www.google.it"));
}
private void webBrowser1_DocumentCompleted(object sender, NavigationEventArgs e)
{
LockWindowUpdate(new IntPtr(0));
}
This should keep the last loaded page on screen until the new page has completed its rendering; as you may imagine, the DLL function simply locks the update of the Window by passing its handle. The handle 0 unlocks it.
Related
I have a test WPF application that has two windows (I'm also using MVC and not MVVM). Both which have one button that should direct the user to the other window.
Initially, I tried this code (I'm only showing the event handlers):
MainWindow.xaml.cs
private static void Button_Click(object sender, RoutedEventArgs e)
{
OtherWindow k = new OtherWindow();
k.Show();
this.Close();
}
OtherWindow.xaml.cs
private static void Button_Click(object sender, RoutedEventArgs e)
{
MainWindow k = new MainWindow();
k.Show();
this.Close();
}
The code works, but I take a look at the memory usage and it increases every time I switch window. Is this normal or is there a way to avoid this and keep the simplicity?
It's very easy to run into memory leaks in WPF, especially when instantiating and disposing of windows multiple times.
I'd recommend taking a look at this page:
http://svetoslavsavov.blogspot.com/2010/05/memory-leaks-in-wpf-applications.html
which details the most common ways to run into a memory leak in WPF and how to fix it.
I'd suggest looking at the Event Handlers and Events from Static Objects sections first.
It seems that you aren't removing your event handlers for your window before closing it, which means that the Window will be kept in memory.
You should also take a look at this thread for good points on disposing of resources correctly. Check out the answer by rookie1024:
What is the correct way to dispose of a WPF window?
I am trying to get the x,y location of a UI element on a wpf page ( not window). In order to make sure the rendering of the page is completed, I place the revoking of PointToScreen inside the Loaded listener. However i get this runtime exception:
This Visual is not connected to a PresentationSource.
void Page_Loaded(object sender, RoutedEventArgs e)
{
.....
Point position = button1.PointToScreen(new Point(0d, 0d));
}
Please let me know what to do? Or could you provide an example how I can run dispatcher for this?
There's no built-in or official way to do this. However you can use the Dispatcher class as a workaround:
private void OnWindowLoaded(object sender, RoutedEventArgs e)
{
Dispatcher.BeginInvoke(new Action(() => YOUR_THING_HERE), DispatcherPriority.ContextIdle, null);
}
The dispatcher will run when nearly all other operations are completed (which will include your rendering)
I had a similar problem myself so this answer is based off this blog article that solved it for me.
EDIT: I was actually wrong
There is a ContentRendered event that serves this purpose.
There are similar questions around here but none that fit into my my particular case scenario.
I have a Windows Form with a Button. The button is attached to the event handler as follows:
private void mybutton_Click(object sender, EventArgs e)
{
// do some processing here
}
In addition there is a combobox where a change in selection in supposed to trigger the button event handler as defined above.
private void mycombobox_SelectedIndexChanged(object sender, EventArgs e)
{
mybutton_Click(sender, e); // this is the line which pops up the dialog
}
The code works exactly as intended at runtime but i get a dialog prompt at compile time which reads:
object reference not set to an instance of an object
There are no other errors or warning.
A google search tells me that this message is an error caused if the program is trying to access a member of a reference type variable which is set to null.
However when i run this code in debug mode, both the sender and event(e) variables are not null.
So why is this dialog popping up ?
And if this had been an error or warning - it should have shown as an error or warning but nothing of that sort happens.
Here's the screenshot:
Edits: Answering Questions Raised in Comments
There are no errors as you can see in the screenshot.
The program works great - just this pop up
The popup is caused by the line:mybutton_Click(sender, e); in the combobox selectedIndexChanged function.
The mybutton_Click(sender, e) does not use any of the arguments sender or e in the processing.
I have not installed any VS extensions either.
It is not a good design to call the Click-event of the button in the SelectedIndexChanged-event of the ComboBox and this might also be the reason for the error.
Better put your logic in a seperate method and call it in the Click- and the SelectedIndexChanged-event like this:
private void UpdateSomething()
{
// Do whatever you want
}
private void mybutton_Click(object sender, EventArgs e)
{
UpdateSomething();
}
private void mycombobox_SelectedIndexChanged(object sender, EventArgs e)
{
UpdateSomething();
}
I think what is happening is that the events are firing in Design mode (which I seem to recall happening to me a few times when using WinForms back in the day).
To get around it what I did was handled the form load event, then in that I attached a listener to the SelectedIndexChanged. Then in Design mode the event isnt bound and wont fire, but at run time it is bound.
Something like:
public void form_OnLoaded(object sender, EventArgs e)
{
myComboBox.SelectedIndexChanged += mycombobox_SelectedIndexChanged;
}
I created a UserControl with the buttons Save, Close and Cancel. I want to close the form without saving on the Cancel button, prompt a message to save on the Close button and Save without closing on the Save button. Normally, I would have used this.Close() on the Cancel button, but the UserControl doesn't have such an option. So I guess I have to set a property for that.
Scrolling down the "Questions that may already have your answer" section, I came across this question: How to close a ChildWindow from an UserControl button loaded inside it? I used the following C# code:
private void btnCancel_Click(object sender, EventArgs e)
{
ProjectInfo infoScreen = (ProjectInfo)this.Parent;
infoScreen.Close();
}
This does the job for one screen, but I wonder if I have to apply this code for all the screen I have? I think there should be a more efficient way. So my question is: Do I need to apply this code for every form I have, or is there another (more efficient) way?
you can use
((Form)this.TopLevelControl).Close();
you can use the FindForm method available for any control:
private void btnCancel_Click(object sender, EventArgs e)
{
Form tmp = this.FindForm();
tmp.Close();
tmp.Dispose();
}
Do not forget to Dispose the form to release resources.
Hope this helps.
You also can close one form in any part of the code using a remote thread:
MyNamespace.MyForm FormThread = (MyNamespace.MyForm)Application.OpenForms["MyForm"];
FormThread.Close();
I found the simple answer :) I all ready thought of something like that.
To close a WinForm in a ButtonClicked Event inside a UserControl use the following code:
private void btnCancel_Click(object sender, EventArgs e)
{
Form someForm = (Form)this.Parent;
someForm.Close();
}
I'm new to WPF and coming from a C++ background so maybe I'm worry about memory management too much here.
Anyways, I've got a UserControl (NewContact) that has a grid with 2 columns, upper column displays 3 radio buttons and depending on which is selected it loads the appropriate UserControl into the lower section of the grid.
private void newMilitaryContactRadioButton_Checked(object sender, RoutedEventArgs e)
{
UserControl NMC = new NewMilitaryContact();
NewContactWindowGridDisplay.Children.Insert(1, NMC);
}
private void newMilitaryContactRadioButton_Unchecked(object sender, RoutedEventArgs e)
{
NewContactWindowGridDisplay.Children.RemoveAt(1);
}
private void newLegalContactRadioButton_Checked(object sender, RoutedEventArgs e)
{
UserControl NLC = new NewLegalContact();
NewContactWindowGridDisplay.Children.Insert(1, NLC);
}
private void newLegalContactRadioButton_Unchecked(object sender, RoutedEventArgs e)
{
NewContactWindowGridDisplay.Children.RemoveAt(1);
}
private void newFirmContactRadioButton_Checked(object sender, RoutedEventArgs e)
{
UserControl NFC = new NewFirmContact();
NewContactWindowGridDisplay.Children.Insert(1, NFC);
}
private void newFirmContactRadioButton_Unchecked(object sender, RoutedEventArgs e)
{
NewContactWindowGridDisplay.Children.RemoveAt(1);
}
Now my question is whether I should be, and how to, unload the UserControls I create, when a radio button is unchecked. I did some searching around MSDN documentation and saw that the using the remove method from the parent object would unload the usercontrol. If that is the case is the code I'm using to in the various "unchecked" methods correct so as not to pile up a ton of NFC/NLC/NMC UserControl objects if someone were to click amongst the three radio buttons over and over and over again?
Much thanks to anyone to who can explain this to me :)
Actually you need to read more about .Net memory management and know how it works. In your case it depends on what your UserControls are doing? If they are using system resources it will good to dispose their references in UserControl unloaded events, otherwise GC will take care of them.
Read this article :
Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework
Also the way you are going is not so good, because soon you will find out you need to do more with your UserControl like setting its DataContext, Styles handling events and etc... and this will hard to do with code.