tags:

views:

640

answers:

2

I need something to get the position of a sub-sub element relative to the container. TransformToAncestor does that. However, the element and subelements move, resize change, their layout, etc. I need a way to keep the position up-to-date. Like an event if anything happend that would affect my TransformToAncestor operation. Or an "AbsolutePosition" dependency property I can bind to.

Background:

I'm doing sort of a work flow editor. There are 'modules' that have one or more ports and lines that connect the modules from port to port.

The XAML stucture looks like this:

<Canvas>
  <Module Left="..." Top="..." Width="..." Height="...">
    <Grid><otherelement><somemorelayouting>
      <Port Name="a" />
      <Port Name="b" />
    </somemorelayouting></otherelement></Grid>
  </Module>
  <Module Left="..." Top="..." Width="..." Height="...">
    <differentsetoflayouts>
    <Port Name="c" />
    <Port Name="d" />
    </differentsetoflayouts>
  </Module>
  <Line startpoint="{binding source=a, path=abs_position}" endpoint="{binding source=c, path=abs_position}" />
</Canvas>

The line connects port a of the first module with port b of the second. The end points should be at the top left corner of the port-element (for the moment). This "abs_position" property used in this example does unfurtunatly not exist (I'm using start/endpoint here instead of X1,X2,Y1,Y2 only to improve readability)

+2  A: 

If you implement your container with attached dependency properties for location of children elements (like the Canvas panel does, which seems to be the case according to provided code), then you can bind to changes of that dependency property using a DependencyPropertyDescriptor.

DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(Canvas.TopProperty, typeof(Canvas));

dpd.AddValueChanged(canvas1, new EventHandler(topChangedCallback));
kek444
The problem is, that the Module is a UserControl with a quite complicated internal structure, using several nested containers of different type. To make things worse, part of that structure is dynamically created. I would need to add event listeners to every single container, each using other properties for positioning. This would work, but its hardly a nice solution. I was hoping for a solution that does not leave the XAML and C# code cluttered with event registering/unregistering.
Lawnmower
Well, then, why did you ask about a DependencyProperty you could bind to?
kek444
Well, I didn't. I asked for "a way to keep the position up-to-date". I just mentioned "AbsolutePosition" dependency property and events as a possible approches. Sorry, I hoped to make the question more clear that way. It seems I have failed.
Lawnmower
You should note that wpf approach is to create a custom Panel which would do custom layout your require, combined with the use of FrameworkPropertyMetadataOptions.AffectsMeasure and FrameworkPropertyMetadataOptions.AffectsArrange on dependency properties which affect layout. Otherwise, you could try implementing your own layout notifications from the ArrangeOverride method of a, say, custom Canvas which you would reuse?
kek444
I see now that for this task, a custom layout would be appropriate. It results in nicer and faster code. Also once the module implemented that way, your original answer solves my problem.Thanks a lot for your answer and your advice!
Lawnmower
+2  A: 

I propose to use kek444's solution with a custom layout if possible. However should this not be applicable, here is another approch I found while googling kek444's hints.

The event UIElement.LayoutUpdated is fired whenever something on the layout changes. It reacts to movement, resize, add/remove of elements, and about anything anything else. It does not only fire if the element is affected on which the event is registered, but also if any other element using the same dispatch thread is touched. As a result it is fired very often, so using it might have quite some performance impact.

See also Dave Relyea's blog entry. Stackoverflow does not let me post two links, so just google for "Layout Events - SizeChanged and LayoutUpdated".

Lawnmower