getting ActualWidth after Layout updates

I'm writing a Control in WPF, and I need the ActualWidth value for my control for initialization and any other time that the layout gets updated.

I understand a little bit about the Layout System now (after working on this for most of the day), and I have found a workaround that I can get by on for now, but I want to figure out the proper way to do this.

Here's the problem:

OnInitialized executes before the Layout is applied, so I can't do anything during initialization that requires values that get set by the Layout System.

I think I need something like an OnUpdateLayout event handler, but I don't see anything like this on MSDN.

The workarounds I've found are to use Dispatcher to call the layout-dependent initialization code after the Layout is rendered -- or to use the Render event on CompositionTarget to repeatedly check for a positive value in ActualWidth. Both of these seem like hacks, and neither of them do anything about Layout updates that occur after initialization.

I found a post on channel9 where someone suggested calling Measure and then using the DesiredSize property, but this doesn't help me because I can't use the DesiredSize since my control doesn't determine it's own width -- the consumer needs to set it to anything they want.

Any help would be much appreciated. BTW, I'm fairly new to C# and coming from a JScript/Actionscript background.

Thanks!

nathan

[1463 byte] By [n8tron] at [2008-1-4]
# 1

At what point do you need to know you're width that it's not already determined? With some more info we may be able to guide you in the right direction with WPF. If you're doing your own rendering (i.e. overriding OnRender) then your ActualWidth will be set by the layout system at that point.

HTH,
Drew

DrewMarsh at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 2

Depending on what you're actually attempting, here are a few options:

  • Controls have a SizeChanged event that is raised anytime the size (ActualWidth/Height) changes
  • Panels can be overridden to get access to the size (arrangement) of controls. Consider panel derived from Canvas for example, overriding ArrangeOverride (calling the base first and then using the results as needed).
  • UIElements all have an event, LayoutUpdated -- which might be useful, again depending on your needs.
WPCoder at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 3
Thank you.

I am very much a newbie to C# -- can you point me to any helpful samples or documentation for the solutions you recommended? Both SizeChanged and LayoutUpdated look like exactly what I'm looking for. I tried a few things, but creating event handlers apparently isn't anything like what I'm used to with JScript/Actionscript.

I started going down the ArrangeOverride path but it seemed like as much work as my other workarounds, and didn't seem to be helping the readability of my code.

Nathan

n8tron at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 4

There are a few ways:

IF you use Xaml,

Code Snippet

<Canvas x:Name="myCanvas" LayoutUpdtaed="myCanvas_LayoutUpdated" ...>

...

</Canvas>

Then, in C# you'll need a method matching the signature of an EventHandler:

Code Snippet

private void myCanvas_LayoutUpdated(object sender, EventArgs e)

{

// .. do whatever you want here ...

}

Or from code you can wire the event (in the constructor):

Code Snippet

myCanvas.LayoutUpdated += new EventHandler(myCanvas_LayoutUpdated);

You only need to do it one way. You don't need to name the control, x:Name="...", unless you're going to use it from code like in the second technique.

WPCoder at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 5

To be perfectly honest, it seems like you're going down the wrong path. If you can explain what you're trying to accomplish we might be able to help you figure out the best way to accomplish it in WPF.

Good luck,

Drew

DrewMarsh at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 6

I am creating my own user control which I am calling RangeSlider because it behaves similarly to a Slider except it has two grippers for setting a BeginRangeValue and an EndRangeValue.

Here's an ASCII representation of my control:

--O=====O--

So I have set up all the PART_ elements in Blend, and my next goal was to create the dependancy properties in the codebehind file -- but I got stuck at the very beginning just trying to initialize the elements with the properties I have (which are not yet set up as dependancy properties). I have two double properties: FromValue and ToValue, which can range from 0 to 1. So in the ASCII art above I'm representing what it would look like with a FromValue of .2 and a ToValue of .8

Just to make sure the idea is clear, here are a couple of other possible states for my RangeSlider control:

FromValue = 0

ToValue = 1

O=========O

FromValue = .8

ToValue = 1

--O=O

I wouldn't be surprised if I am going about this wrong. This is my first control, and its the deepest I've gone with C# so far. It seems odd to me to have nearly 80 lines of code to describe such a simple control just to display (before setting up the properties as dependency props or adding routed events, or even creating any of the behavior). Any suggestions, samples, or relevant reference anyone can point me to would be greatly appreciated.

Thanks!

n8tron at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 7

Thank you!!

This is exactly what I was looking for.

Alternative suggestions for my design are still welcome, however.

n8tron at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 8

A Slider is a reasonably complicated control with one Thumb -- having two will make it extra tricky!

Maybe someone has done this control before (with source). I haven't come across it (but would like to see it). Here's the general path I was thinking for a reasonably simple implementation:

Start with a new control. Put 2 shapes on the control (placeholders for whatever your final look would be). In the PreviewMouseMoveDown event for the control, check where the mouse is -- which 'thumb' is the user over. Start tracking the movement. You'll want to look at the event args for that e.MouseDevice.GetPosition(...).

Set a DP property corresponding to that thumb for the current value that has the FrameworkPropertyMetadataOption of AffectsArrange set. You'll need two DP properties representing the high and low minimally. (From & To you called them).

In the ArrangeOverride, position the thumb(s) accordingly. You'll want to handle MeasureOverride as well for things to size correctly. You shouldn't need anything related to Layout updated, etc.

IF you use two thumb controls as 'shapes', you'll get some 'free' drag action in terms of capturing the mouse and having it update you with new deltas via the DragStarted, DragDelta and DragComplted events. If you don't use the thumb, you'll need to Capture the mouse and Release the mouse (CaptureMouse and ReleaseMouse), so that the mouse move events are sent to your control even when the user moves off of your control (and most usefully, so you know when they've released the mouse button -- even when it was pressed down over your control, dragged off your control, and then released). I'd definitely recommend you use the Thumbs if you can. You can style them if you want.

You'll need a third control to draw the fill area -- pick your favorite.If you want functionality when that region is clicked, consider a styled button for example.

Or you could try to derive from Slider, override the necessary functions, extend the track control used internally to include an extra thumb ... bam. that's a lot of work!

Hope this gets you going in the right direction.

WPCoder at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 9

I finished it using the approach described here.

The behavior was pretty simple -- I just have MouseDown and MouseUp events for setting a boolean that tracks dragging for each "thumb" (as you call them). Then in my Render event I'm updating the associated value based on the Mouse position relative to the control's ActualWidth and calling an Update method to position the thumb accordingly. You're right that I had to Capture the Mouse to get the expected behavior.

I am using LayoutUpdated to initialize all the elements in the control (so it displays according to whatever is set in Blend) and to ensure that the control responds properly if the user resizes the window. Thanks for the tip -- next time I work run into this issue I will look into using the ArrangeOverride and MeasureOverride for this.

I didn't know that there was any 'free' drag behavior. Can you point me to further reference or examples of using this?

Also, I didn't know there was a Thumb control that I could implement.

Thanks again!

n8tron at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 10
The Thumb class in the System.Windows.Controls.Primitives namespace provides functionality that can help with your scenario as noted above. This namespace contains base classes and controls that are intended to be used as part of other more complex controls.

The thumb control is used by the built-in WPF slider control. It provides the following events that can be of help in your scenario:

DragStarted
DragDelta
DragCompleted

Please take a look at the sample and the how to article. You can use styles and templates to achieve a different visual appearance for the Thumb control. I hope this helps.

-Ahmed

AhmedChaudhary at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 11
n8tron - do you have the code for your finished control? I am doing pretty much the exact same thing and struggling. Would save me a lot of time! Thanks.
DiamonDogX at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 12

Hey, DiamonDogx. I hope it isn't too late for this to be useful to you (sorry, I haven't been on the forum in a while).

How can I deliver the files to you? It seems like a lot to post here (the Codebehind is about 200 lines and the XAML is 500 lines, and you'll want to see an example of it implemented, which is another 1000 or so lines.

n8tron at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 13
How about email? Sounds like the file size shouldn't be a problem. My address: brad@bradicus.com

Thanks! Really appreciate it!

DiamonDogX at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...

Visual Studio Orcas

Site Classified