views:

599

answers:

3

Hello all,

In silverlight Canvas class (with Reflector) has very simple implementation: 3 attached dependency properties (Left, Top, ZIndex) and 2 ovverides of MeasureOverride and ArrangeOverride methods which do nothing special.

But if i use my implementation like:

class MyCanvas : Panel { /* Top and Left dependency properties implementation */ }

And then use MyCanvas in XAML like standard Canvas. That's not working as expected (i see the empty screen).

How Canvas was implemented?

-- Additional code: MyCanvas.cs

public class MyCanvas : Panel
{
    public static double GetTop(DependencyObject obj)
    {
        return (double)obj.GetValue(TopProperty);
    }

    public static void SetTop(DependencyObject obj, double value)
    {
        obj.SetValue(TopProperty, value);
    }

    // Using a DependencyProperty as the backing store for Top.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TopProperty =
        DependencyProperty.RegisterAttached("Top", typeof(double), typeof(MyCanvas), new PropertyMetadata(0.0));


    public static double GetLeft(DependencyObject obj)
    {
        return (double)obj.GetValue(LeftProperty);
    }

    public static void SetLeft(DependencyObject obj, double value)
    {
        obj.SetValue(LeftProperty, value);
    }

    // Using a DependencyProperty as the backing store for Left.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty LeftProperty =
        DependencyProperty.RegisterAttached("Left", typeof(double), typeof(MyCanvas), new PropertyMetadata(0.0));
}

Used in XAML like:

<local:MyCanvas>
    <Rectangle 
        local:MyCanvas.Left="10"
        local:MyCanvas.Top="10"
        Width="100"
        Height="100"
        Fill="Black" />
</local:MyCanvas>

if change MyCanvas to standard Canvas, i can view black-filled rectangle at position 10,10.

<Canvas>
    <Rectangle 
        Canvas.Left="10"
        Canvas.Top="10"
        Width="100"
        Height="100"
        Fill="Black" />
</Canvas>
+1  A: 

Canvas is nothing more than a Panel with Left and Top attached properties, as you said. According to MSDN:

Defines an area within which you can explicitly position child objects by using coordinates that are relative to the area.

That's it- a Canvas can have an explicit location inside another FrameworkElement-derived container. If you're not seeing your handrolled Canvas, you may have a rendering error. Have you tried changing the background color to make sure you can see it?

Dave Swersky
Its not rendering error, its some hidden magic in silverlight implementation.If i implement my own arrange algorithm i can view children elements on MyCanvas, but real Canvas do not realize any arrange behavior.I find some suspicious details: DependencyProperty.RegisterCoreProperty([constant], typeof(double)); instead DependencyProperty.RegisterAttached for registering Left and Top properties.
Andir
A: 

I can implement MeasureOverride and ArrangeOvverride something like:

    protected override Size MeasureOverride(Size availableSize)
    {
        foreach (var element in Children)
            element.Measure(availableSize);
        return base.MeasureOverride(availableSize);
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        foreach (var element in Children)
        {
            var left = GetLeft(element);
            var top = GetTop(element);
            var size = element.DesiredSize;
            element.Arrange(
                new Rect(left, top, size.Width, size.Height)
                );
        }
        return base.ArrangeOverride(finalSize);
    }

And i can view black rectangle as expected in my example of MyCanvas usage.

But Canvas not implement these methods. How does it work?!

Andir
A: 

This seems to be a bug in the Silverlight disassembling engine of Reflector. You can build your own Silverlight Canvas control with the following steps:

  • Disassemble the WPF canvas control in Reflector and copy the code to Visual Studio.
  • Remove the DependencyProperties Bottom and Right, as well as their Get and Set methods.
  • Remove the Bottom and Right clauses from ArrangeOverride.
  • Replace FrameworkPropertyMetadata by PropertyMetadata.
  • Remove the property validation arguments from the DependencyProperty initialization.

Be aware that the Canvas created this way does not have a ZIndex property.

cheeesus
That's not Reflector bug. Most of silverlight core functionality was implemented in native agcore.dll.And Canvas implementation use "core dependency properties" for "hide" own implementation details (look to DependencyProperty.RegisterCoreProperty internal method).
Andir