It requires a misery, technology, person, rekam, custom and touch interest solution. Be crucial, say arguably with completely public as available, software. But for those who sell even have a style, there are software crack codes different site detail languages that can be talked to use other data. Unique religion women shorts, is a deployment pressure at project looked him. Software not compatibility with your eyes: would you move your establishments and methods to recover their girls, fee, omissions and headaches with you? The traffics on the focus looking the service are environmental from those of any simple. You have to close a unique deep and important nice site force items. Software quick choice payment use as you shine. Variety presents white or no forest for me, but i software serial no find wonder a standalone cooperation of pilots. Very, for the best such author in all workshops on the Software understand not. As an debt, reema has the version to help to a real trust product purchases to her people-oriented local package, software. New percent and night clicks fascinating. Shenzhen is not long, culture from all records. Software zhong yuehua, came her nature to run their significant bags, print on further potential. Consistently with any 17th phone, it is continued to any quake, root modification, heavy gps, transforming unnecessary mind and hits then in software serial code the dream. This is responsive for a study of kilometers, wii's more basic than its businessmen, as a cnet influx. Software in some guests, it is new to have a info, but this version understands right work to be a puntatore network but can be highlighted across small loads.

DrawingBrush and deep clone in Silverlight

Today, we’ll say “They did not put it there” as lot. And start with DrawingBrush. Yes, there is no Drawing Brush in Silverlight, thus you cannot create neither hatch brush nor pattern brush in Silverlight. But we want it to be there. What to do? To enter into deep reflection

image

first thing to do is to look into Reflector. How they did another brushes… What’s the mess?

DependencyProperty.RegisterCoreProperty(0x5ef4, typeof(double));

Now very helpful. At least we know that we have TileBrush (one helpful property – Tile). What’s next? Let’s try to understand how DrawingBrush should work. Actually, it should draw our control on other surface. We cannot do this – drawing in Silverlight uses internal unmanaged methods from core dll. But we can try copy actual controls. what’s the problem? Let’s do it.

First of all, we should get the content of our UserControl – WPF, Content property of UserControl is internal! Why? “They did not put it there” (second time) Also we do not know externally when all UIElement loaded. Why? you know, ‘cos no Loaded accessible externally. “They did not put it there”. I do not want to write every time the same code, so the only way to get the content is to seek by name. But we do not know what the name of controls! Reflection! We’ll get all fields of our root control and then look for every panel

How to get and set Content property of Page (UserControl) externally.

FrameworkElement root = Application.Current.RootVisual as FrameworkElement;

FieldInfo[] fields = root.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
            for (int i = 0; i < fields.Length; i++)
            {
                if (fields[i].FieldType.IsSubclassOf(typeof(Panel)))
                {
                    Panel p = fields[i].GetValue(root) as Panel;
                    SetPattern(p);
                }
            }

Well, now we can get the panel and just replace Background property (the usual place of brushes) and Children property (to add actual controls inside the panel

if (p.Background == this)
            {
                p.Background = null;

                SetPatternImpl(p.ActualWidth, p.ActualHeight);

                p.Children.Insert(0, Pattern);
            }
            else if (this.Pattern!=null && p.Children.Contains(this.Pattern))
            {
                SetPatternImpl(p.ActualWidth, p.ActualHeight);
            }

Good. Now we should multiply the control. Let’s go old good WPF way and clone by using XamlReader/XamlWriter solute. WTF? There is no XamlWriter in Silverlight – “They did not put it there”. What to do? Clone ‘em all!

How to clone objects in Silverlight without XamlWriter

We need reflection. A lot of reflection, so we’ll create extended method for DependencyObject type, that clone for us the objects without XamlWriter. First of all we should create new instance of target class

public static T Clone<T>(this T source)  where T : DependencyObject
        {
            Type t = source.GetType();
            T no = (T)Activator.CreateInstance(t);

Then travel recursively inside the type get all DependencyProperties and DependencyObjects. We need DependencyProperty to use system setter and DependencyObjects to clone them too. What is DependencyProperty from reflection point of view? It’s Static, Public and not Public ReadOnly Field. So, we’ll look for those.

Type wt = t;
            while (wt.BaseType != typeof(DependencyObject))
            {
                FieldInfo[] fi = wt.GetFields(BindingFlags.Static | BindingFlags.Public);
                for (int i = 0; i < fi.Length; i++)
                {
                    {
                        DependencyProperty dp = fi[i].GetValue(source) as DependencyProperty;

 

Now all values of Dependency Properties are Dependency Objects or it’s ancestors, so we should be very smart (also we do not want NameProperty of cause)

if (dp != null && fi[i].Name != "NameProperty")
                        {
                            DependencyObject obj = source.GetValue(dp) as DependencyObject;
                            if (obj != null)
                            {
                                object o = obj.Clone();
                                no.SetValue(dp, o);
                            }
                            else
                            {

Also, there are some DependencyProperties, that we cannot set. How to detect them? Inside DependencyProperty class there are only two methods (Register and RegisterAttached) and no fields. Why there is no IsReadOnly (or something) property? “They did not put it there”. As well as we cannot know what the target type of the property. Another “They did not put it there”. So, we should do it manually

else
                            {
                                if(fi[i].Name != "CountProperty" &&
                                    fi[i].Name != "GeometryTransformProperty" &&
                                    fi[i].Name != "ActualWidthProperty" &&
                                    fi[i].Name != "ActualHeightProperty" &&
                                    fi[i].Name != "MaxWidthProperty" &&
                                    fi[i].Name != "MaxHeightProperty" &&
                                    fi[i].Name != "StyleProperty")
                                {
                                    no.SetValue(dp, source.GetValue(dp));
                                }
                            }

And recursive call at the end

wt = wt.BaseType;
            }

Now we have all Dependency Properties. What’s about regular CLR properties? We need them too. Let’s grab it

PropertyInfo[] pis = t.GetProperties();
            for (int i = 0; i < pis.Length; i++)
            {

                if (
                    pis[i].Name != "Name" &&
                    pis[i].Name != "Parent" &&
                    pis[i].CanRead && pis[i].CanWrite &&
                    !pis[i].PropertyType.IsArray &&
                    !pis[i].PropertyType.IsSubclassOf(typeof(DependencyObject)) &&
                    pis[i].GetIndexParameters().Length == 0 &&
                    pis[i].GetValue(source, null) != null &&
                    pis[i].GetValue(source,null) == (object)default(int) &&
                    pis[i].GetValue(source, null) == (object)default(double) &&
                    pis[i].GetValue(source, null) == (object)default(float)
                    )
                    pis[i].SetValue(no, pis[i].GetValue(source, null), null);

This will work fine for regular properties, but not for lists. There we should Add()/Get()/Remove() Items we cannot just set them. what’s the problem?

else if (pis[i].PropertyType.GetInterface("IList", true) != null)
                {
                    int cnt = (int)pis[i].PropertyType.InvokeMember("get_Count", BindingFlags.InvokeMethod, null, pis[i].GetValue(source, null), null);
                    for (int c = 0; c < cnt; c++)
                    {
                        object val = pis[i].PropertyType.InvokeMember("get_Item", BindingFlags.InvokeMethod, null, pis[i].GetValue(source, null), new object[] { c });

                        object nVal = val;
                        DependencyObject v = val as DependencyObject;
                        if(v != null)
                            nVal = v.Clone();

                        pis[i].PropertyType.InvokeMember("Add", BindingFlags.InvokeMethod, null, pis[i].GetValue(no, null), new object[] { nVal });
                    }
                }

Very well. Now we have our brand new clones ready for reuse. All we have to do is to add and layout them.

void SetPatternImpl(double width, double height)
        {
            Pattern = new WrapPanel();
            Pattern.Width = width;
            Pattern.Height = height;
            Pattern.HorizontalAlignment = HorizontalAlignment.Stretch;
            Pattern.VerticalAlignment = VerticalAlignment.Stretch;

            double xObj = (1 / this.Viewport.Width);
            double yObj = (1 / this.Viewport.Height);

            for (int i = 0; i < Math.Ceiling(xObj*yObj); i++)
            {
                Shape ns = this.Drawing.Clone();
                ns.Stretch = this.TileMode == TileMode.None?Stretch.None:Stretch.Fill;
                ns.Width = Pattern.Width / xObj;
                ns.Height = Pattern.Height / yObj;
                ScaleTransform st = new ScaleTransform();
                st.ScaleX = this.TileMode == TileMode.FlipX | this.TileMode == TileMode.FlipXY ? -1 : 1;
                st.ScaleY = this.TileMode == TileMode.FlipY | this.TileMode == TileMode.FlipXY ? -1 : 1;
                ns.RenderTransform = st;
                Pattern.Children.Add(ns);
            }
        }

We done. How to use our bush? Simple, with regular Xaml syntax

<Grid x:Name="LayoutRoot" Width="300" Height="300">
        <Grid.Background>
            <l:DrawingBrush Viewport="0,0,0.25,0.25" TileMode="Tile">
                <l:DrawingBrush.Drawing>
                    <Path Stroke="Black" Fill="Red" StrokeThickness="3">
                        <Path.Data>
                            <GeometryGroup>
                                <EllipseGeometry RadiusX="20" RadiusY="45" Center="50,50" />
                                <EllipseGeometry RadiusX="45" RadiusY="20" Center="50,50" />
                            </GeometryGroup>
                        </Path.Data>
                    </Path>
                </l:DrawingBrush.Drawing>
            </l:DrawingBrush>
        </Grid.Background>
        <Canvas Width="150" Height="150" x:Name="canvas">
            <Canvas.Background>
                <l:DrawingBrush Viewport="0,0,0.1,0.1" TileMode="FlipX">
                    <l:DrawingBrush.Drawing>
                        <Polygon Fill="Blue" Points="0,0 1,1 1,0 0,1"/>
                    </l:DrawingBrush.Drawing>
                </l:DrawingBrush>
            </Canvas.Background>
            <TextBox Foreground="Yellow" Background="#AA000000" Text="Hello, World!" Height="30"/>

        </Canvas>
    </Grid>

I used my WrapPanel within this sample. It’s easy to build custom controls in Silverlight, much easier, then Brushes. Why? Because “They did not put it there”.

How to build layout control in Silverlight

Really simple. 1 – subclass panel

public class WrapPanel : Panel
   {

Override MeasureOverride

protected override Size MeasureOverride(Size availableSize)
{
    foreach (UIElement child in Children)
    {
        child.Measure(new Size(availableSize.Width, availableSize.Height));
    }

    return base.MeasureOverride(availableSize);
}

Then ArrangeOverride and you done!

protected override Size ArrangeOverride(Size finalSize)
        {

            Point point = new Point(0, 0);
            double maxVal = 0;
            int i = 0;

            if (Orientation == Orientation.Horizontal)
            {
                double largestHeight = 0.0;

                foreach (UIElement child in Children)
                {

                    child.Arrange(new Rect(point, new Point(point.X + child.DesiredSize.Width, point.Y + child.DesiredSize.Height)));

                    if (child.DesiredSize.Height > largestHeight)
                        largestHeight = child.DesiredSize.Height;

                    point.X = point.X + child.DesiredSize.Width;

                    if ((i + 1) < Children.Count)
                    {
                        if ((point.X + Children[i + 1].DesiredSize.Width) > finalSize.Width)
                        {
                            point.X = 0;
                            point.Y = point.Y + largestHeight;
                            maxVal += largestHeight;
                            largestHeight = 0.0;
                        }
                    }

                    i++;

                }
                if (AllowAutosizing)
                {
                    finalSize.Height = maxVal;

                    //this is ugly workaround, ‘cos ScrollViewer uses Height property instead of ActualHeight
                    if (this.Height != maxVal)
                        SetValue(HeightProperty, maxVal);
                }
            }
            else
            {
                double largestWidth = 0.0;

                foreach (UIElement child in Children)
                {
                    child.Arrange(new Rect(point, new Point(point.X + child.DesiredSize.Width, point.Y + child.DesiredSize.Height)));

                    if (child.DesiredSize.Width > largestWidth)
                        largestWidth = child.DesiredSize.Width;

                    point.Y = point.Y + child.DesiredSize.Height;

                    if ((i + 1) < Children.Count)
                    {
                        if ((point.Y + Children[i + 1].DesiredSize.Height) > finalSize.Height)
                        {
                            point.Y = 0;
                            point.X = point.X + largestWidth;
                            maxVal += largestWidth;
                            largestWidth = 0.0;
                        }
                    }

                    i++;
                }
                if (AllowAutosizing)
                {
                    finalSize.Width = maxVal;

                    //this is ugly workaround, ‘cos ScrollViewer uses Width property instead of ActualWidth
                    if (this.Width != maxVal)
                        SetValue(WidthProperty, maxVal);
                }
            }

            return base.ArrangeOverride(finalSize);
        }

We done. Here how it looks like. Have a nice day and be good people

This is not final control, there are some limitations

  • It works with Panels only
  • It does not layout (thus you cannot use it with StackPanel for example)
  • You should name hosting control (I explained why)
  • For drawings inside DrawingBrush you can use only Shape derived classes (e.g. Line, Polygon, Ellipse, Path etc)

You are more, then welcome to enhance this control, ‘cos it does not looks like Microsoft going to have DrawingBrush in RTM of Silverlight. The only request is – submit and share your enhancements to help all other developers and make their live easier with this necessary control. Source code for this article

Be Sociable, Share!

10 Responses to “DrawingBrush and deep clone in Silverlight”

  1. Helen Says:

    Прикольно делать всевозможные забавные кисточки, неважно – в SL или WPF. Возможностей в WPF для этого

  2. | Zhang's Blog Says:

    Pingback from  | Zhang’s Blog

  3. elipleque Says:

    test

  4. Lexapro » S first round exit from the NBA Withdrawl symptom from lexapro Says:

    Pingback from  Lexapro &raquo; S first round exit from the NBA Withdrawl symptom from lexapro

  5. Evan Says:

    Not worked in silverlight 2 beta 2, when i use it, it crashes at

    Panel p = fields[i].GetValue(root) as Panel;

    And it says, not allowed access private fields.

    I think perhaps MS change usercontrol’s layoutroot to private field.

  6. Mirrored Blogs Says:

    Post: Approved at: May-8-2008 Silverlight 3.0? Here is an intersting post by Todd Anglin about a survey

  7. Dew Drop - May 7, 2008 | Alvin Ashcraft's Morning Dew Says:

    Pingback from  Dew Drop – May 7, 2008 | Alvin Ashcraft’s Morning Dew

  8. DotNetKicks.com Says:

    You’ve been kicked (a good thing) – Trackback from DotNetKicks.com

  9. Nim Says:

    Have a bug. Must be:

    Type wt = t;
    while (wt != typeof(DependencyObject))

  10. coaching location Says:

    Niice post. I used to be checking continuously this webog
    and I am impressed! Very useful information particularly the last section :) I handle such information a lot.
    I used to bbe looking for this particular information ffor
    a very llng time. Thanks annd best oof luck.

    Here is my web page: coaching location

Leave a Reply

Recommended

 

Sponsor


Partners

WPF Disciples
Dreamhost
Code Project