When are WPF elements ready to use? - wpf

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.

Related

Click event on canvas with background

I have UserControl, which contains Canvas (in Grid).
When I just clicked on canvas event PreviewMouseLeftButtonDown or MouseLeftButtonDown works perfectly, but when I set canvas.Background = new ImageBrush(imgs); and try to click on canvas, events doesn't raising. I tried to make same events for grid (canvas parent), but result was the same.
UPD1: canvas has children - rectangle (from System.Windows.Shapes) around cursor, maybe it somehow affect on events.
In wpf there are two possible scenarios where hit testing (clicking with mouse somewhere) is not working. These two are ment to be that way and it is by design. I am talking about when your Background is NULL or when you have the property IsHitTestVisible set to false.
In any other case hit testing/clicking will work.
I assume your background is null somehow. Maybe imgs throws error which will be catched in an empty try/catch block internally at render time.
Tell us is the background property of your canvas null?
There is a nice tool called Snoop which allows you to snoop an wpf app and change properties at runtime. Use that tool to change the background and tell us about the results.
EDIT:
First of all the default value of Canvas Background is null therefore by default you can click as often you wish on Canvas and nothing will happen.
As soon you change the Background to Yellow it clicking will work and your handler will be called.

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).

Redraw and flicker issues

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;

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).

WPF Close UserControl in Frame and access Parent Controls

I have a WPF app with a Window (RootWindow) with a Toolbar and a Frame (ContentFrame). Initially the Toolbar is hidden.
I load a Login UserControl into the Frame and when the user correctly logs in I'd like to close the UserControl and then make the Parent Window toolbar visible.
Seems such a simple thing to do.
However, you cannot close a UserControl from within the UserControl. So how do I break out of the UserControl so I can remove it from the RootWindow (ContentFrame.Source=Nothing) and also make the toolbar Visible.
I can get a handle for the Parent Window with the following code but I cannot access the controls within it
Dim parentWindow As Window = Window.GetWindow(Me) 'Get a handle for parent window
Ideally, I'd like to be able to access Parent Window Controls from within a Child UserControl or at least be able to Trigger an event in the Parent Window from the Child UserControl.
To find the parent in the hirearchy you can use this code:
http://www.hardcodet.net/2009/03/detecting-double-click-events-on-the-wpf-datagrid
Although the problem solved in above article is for DataGrid, the code to find parent is generic enough and should work in your case.

Resources