Redraw and flicker issues - winforms

I have an Outlook style app. So basically I have a sidebar on the left and on the right I have a panel control (pnlMainBody) that hosts content.
The content is typically a user control that I add to the panel when user clicks appropriate button in the side bar. The way I add the user control to the panel is as follows:
// _pnlEmails is the User Control that I am adding to the panel
_pnlEmails = new pnlEmails();
_pnlEmails.Dock = DockStyle.Fill;
this.pnlMainBody.Controls.Add(_pnlEmails);
Some of the user controls that I add to the main panel are quite complex UI-wise. So when this.pnlMainBody.Controls.Add(_pnlEmails); fires, I see the control appear on the screen, then it resizes itself to fill the body of the panel control.
It's quite ugly actually, so I was wondering whether there is a way to not show the resizing until it's actually done resizing?
I've tried setting the user control's .Visible to false. I've tried doing .SuspendLayout, all to no avail.
Is there a way to do this so the screen transitions are smooth?

First try to turn on double buffer painting in the parent form by setting:
this.DoubleBuffered = true;
Do that in your load handler or some such place to see if the flicker goes away.
If that doesn't work you can also try to set the DoubleBuffered property to true for the child controls if they are .NET Control-derived entities. Here's some code that I used recently to get controls that did not expose the double buffer property to paint nicely: (vb version. Do you need C#?)
Private Sub ForceDoubleBuffering(ByVal o As Object)
Dim ctrl As Control
Dim method As Reflection.MethodInfo
Dim flags As Reflection.BindingFlags
ctrl = TryCast(o, Control)
flags = Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic
method = ctrl.GetType().GetMethod("SetStyle", flags)
method.Invoke(ctrl, New Object() {ControlStyles.OptimizedDoubleBuffer, True})
End Sub

I figured out the trick to solving the issue. As I long as I set up the Dock.Fill property after adding the control to the main panel, there is no flicker.
this.pnlMainBody.Controls.Add(_pnlEmails);
_pnlEmails.Dock = DockStyle.Fill;

Related

When are WPF elements ready to use?

So i have this piece of programmatically created content that is dependent on the actualWidth/actualHeight values of its parent canvas. When the said content is created during the Loaded event of the parent window though, the width and height of the canvas still appear to be 0. This is corrected as soon as I resize the window via the sizeChanged event but still, I want the stuff to look its best right away.
Is there another event to guarantee the window being ready to use?
heres the loaded event handler
Public Sub onLoad() Handles Me.Loaded
Dim wc As New uiFloaterCanvas <- the item that needs to have correct actualWidth/height values
mainGrid.Children.add(wc) <- grid attatched to the main window in designer
ww = wc.createFloater() <- spawns a usercontrol inside the canvas
ww.place(New DoubleRect(300, 300, 500, 500)) <- fails to do its job because the place sub clips the width/height to actualwidth/height of the canvas
End Sub
Well I figured it out. If I want things to be ready by the Loaded event, I must add them to the layout in Initialized event.

UserControl does not auto resize with the Form

I am having troubles with setting my user control to automatically resize with the panel where it is created. When user is resizing a main form that contains the user control, the size of this user control does not change at all making for some poor user experience.
So far I tried following:
Ensure MinimumSize and MaximumSize properties on the user control are set to 0.
Set AutoSize property on both (1) the user control and (2) the panel where it resides to True
Set Anchor property on the panel to Top, Bottom, Left, Right
Set Dock property to Fill for the user control (I did this with the following code)
These attempts had no effect on the behavior of my user control:
CalcUserControl calcControl = new CalcUserControl(CountryId);
calcControl.Dock = DockStyle.Fill;
panelUserCtrl.Controls.Clear();
panelUserCtrl.Controls.Add(calcControl);
Any suggestions would be much appreciated.
Try setting the AutoSize properties to False.
Also, instead of calling Controls.Clear();, try disposing of the controls inside it, something like:
while (panelUserCtrl.Controls.Count > 0) {
panelUserCtrl.Controls[0].Dispose();
}
Otherwise, you are leaking memory since those removed controls would still exist.
You should set AutoSizeMode to GrowAndShrink too.

How to dynamic add/remove control with Expression Blend?

A while I go, I made a demo application with Expression Blend.
My first screen is a big selections of Buttons, so when user click on any of button, it goes to the MainView.
Then in the MainView, I have a list of Menu items that user can click and shows up its corresponing DisplayView. (Appointment Menu Item will shows up AppointmentView etc).
Everything is good, I can click the MenuItem, the Views shows up with animation and transition effects.
But the thing is, with creating in Expression Blend, the MainView, Menu, AppointmentView etc every thing is predefined in the XAML. So when user load the first screen has to load everything into memory.
Now thinking of it, shouldn't the MainView etc be dynamically add into the screen?
How do I do it with Expression Blend? Or the only way to do is just....do it in code-behind myself (writting StoryBoard etc for the dynamic add/remove controls?)
If there is any example/tutorial of doing it, it will be great.
I guess you have very limited possibilities to conditionally load or unload controls exclusively in Blend without writing code-behind.
In general an opening tag in XAML is equivalent to a parameter-less constructor of some class object. As soon as you write the tags your are instantiating an object but that doesn't mean that it's visual appearance is loaded into memory. This only happens when the control is actually shown on the screen.
In my opinion the leanest way to control the appearance of some control is to use a single-child control. Take a Border control for example and add the user control you want to conditionally load to its child property, so you can decide for example whether to load or unload a control.
But unfortunately I think you have to do this in code as well. Take this easy code snippet:
// either instantiate in code or use from markuup
Border myBorder = new Border();
// the control you want to conditionally appear and disappear
UserControl myUserControl = new UserControl();
myBorder.Child.Add(myUserControl);
Of course a much more sophisticated approach is to use Grids. Here you have to use attached properties to add or remove child elements:
// either instantiate in code or use from markuup
Grid myGrid = new Grid();
// the control you want to conditionally appear and disappear
UserControl myUserControl = new UserControl();
// set the target position inside the Grid via the Grids attached properties
Grid.setRow(myUserControl, 1);
Grid.setColumn(myUserControl, 0);
// actually add the control
Grid.Children.Add(myUserControl);
Although I am pretty sure you were aware of all of that I am hoping it helped a bit :)

WPF custom panel control doesn't respond to mouse events

I've created a custom panel control and would like to have it respond to a mouse move event, however, when I add an event handler like so:
Private Sub FloatingPanel_MouseMove(ByVal sender As Object,
ByVal e As MouseEventArgs) Handles Me.MouseMove
End Sub
It only responds when I move the mouse over one of the child controls within the panel. I need to have it respond whenever I move the mouse anywhere inside the custom panel.
Update:
I found the following question which gave me a clue:
WPF - how to best implement a panel with draggable/zoomable children?
I can get mouse events on the
GraphCanvas itself only if it has a
background at the point
This led me to simply set the background which appears to have resolved the issue... My question now is, why? Why should I have to set the background in order to receive a mousemove event?
Update 2: The following code is what ultimately solved the problem (See Kent's answer below).
Protected Overrides Function HitTestCore(ByVal hitTestParameters As System.Windows.Media.PointHitTestParameters) As System.Windows.Media.HitTestResult
Return New PointHitTestResult(Me, hitTestParameters.HitPoint)
End Function
Thank you,
Matt
For the purposes of hit testing, WPF's default hit testing logic has two modes of transparency. One is transparent both visually and to hit testing (#00000000 or by not setting a background at all), the other is transparent only visually and does not preclude hit testing (##00ffffff). You want the latter.
I believe you could also override UIElement.HitTestCore in your custom Panel such that there is no dependency on having the background set.
I actually suspected this might have been the issue here; If the background of a control is null and there is no other subcomponent there your mouse is not moving across the control but accross the control behind it, so it makes sense that you do not get a mouse event from that (it is not very expected though because the bounds of the control may envelope the area).

Is it possible to autosize WebBrowser control?

I need to display some portion of html in my windows forms application. It's necessary that this html will be displayed without any scrollbars.
I tried to use WebBrowser control for my task, but it lacks of AutoSize property. Is it possible to determine minimal height necessary to display all contents without scrolling somehow?
Set ScrollBarsEnabled to false. Define the size based on your target minimum width. Add a handler to the webbrowser documentcompleted event as follows:
Private Sub WebBrowser1_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
WebBrowser1.Size = WebBrowser1.Document.Body.ScrollRectangle.Size
End Sub
Here's a link to a C# WebBrowser wrapper which may do what you need:
http://www.codeproject.com/KB/miscctrl/csEXWB.aspx?msg=2526724
To do what you need, I think you would access the document on the page and then the element you're displaying, and get its height and width properties, and then adjust your WebBrowser control to be a few pixels larger than that. I think the WebBrowser wrapper control in the link can do the first part of this task (get the element's height and width).

Resources