0

I am trying to create a WPF app that allows you to create rectangles on the screen, resize the rectangles and move them around, and add new re-sizable and movable rectangles on the click of a button.

I don't know much about WPF, so I have found some code that does resizing of shapes here

This resizing works will, but I am now stuck with how to dynamically create a new version of the control. I am using a ContentControl which handles the resizing, and it has an inner Rectangle for display. The xaml looks like the following:

<Window x:Class="MazeBuilder.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="clr-namespace:MazeBuilder"
    Title="MainWindow" Height="480" Width="640">
<Window.Resources>

    <!-- ResizeDecorator Template -->
    <ControlTemplate x:Key="ResizeDecoratorTemplate" TargetType="{x:Type Control}">
        <Grid>
            <s:ResizeThumb Height="3" Cursor="SizeNS" Margin="0 -4 0 0"
                   VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
            <s:ResizeThumb Width="3" Cursor="SizeWE" Margin="-4 0 0 0"
                   VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
            <s:ResizeThumb Width="3" Cursor="SizeWE" Margin="0 0 -4 0"
                   VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
            <s:ResizeThumb Height="3" Cursor="SizeNS" Margin="0 0 0 -4"
                   VerticalAlignment="Bottom" HorizontalAlignment="Stretch"/>
            <s:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="-6 -6 0 0"
                   VerticalAlignment="Top" HorizontalAlignment="Left"/>
            <s:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="0 -6 -6 0"
                   VerticalAlignment="Top" HorizontalAlignment="Right"/>
            <s:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="-6 0 0 -6"
                   VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
            <s:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="0 0 -6 -6"
                   VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
        </Grid>
    </ControlTemplate>

    <!-- Designer Item Template-->
    <ControlTemplate x:Key="DesignerItemTemplate" TargetType="ContentControl">
        <Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">

            <Control Template="{StaticResource ResizeDecoratorTemplate}"/>
            <ContentPresenter Content="{TemplateBinding ContentControl.Content}"/>
        </Grid>
    </ControlTemplate>

</Window.Resources>
    <Canvas x:Name="LayoutRoot" MouseDown="LayoutRoot_MouseDown" MouseMove="LayoutRoot_MouseMove">
    <Popup Name="PopupEsales" Placement="Right" IsEnabled="True" IsOpen="False" Grid.RowSpan="2">
        <ListView Height="145" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="lvSalesPersonIdSearch" VerticalAlignment="Top" Width="257" >
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Sales Persons Id" Width="100" DisplayMemberBinding="{Binding Path=SPID}" />
                    <GridViewColumn Header="Name" Width="100" DisplayMemberBinding="{Binding Path=Name}" />
                </GridView>
            </ListView.View>
        </ListView>
    </Popup>
    <Menu Height="23" IsMainMenu="True" HorizontalAlignment="Left"  Name="menu1" VerticalAlignment="Top" Width="640">
        <MenuItem Header="File">
            <MenuItem Header="New Maze"  Click="New_Click" />
            <MenuItem Header="Load Maze" Click="Load_Click" />
            <MenuItem Header="Save Maze" Click="Save_Click"  />

        </MenuItem>
        <MenuItem Header="Tools">
            <MenuItem Header="Show"  Click="ShowTools_Click" />
        </MenuItem>
    </Menu>

    <ContentControl  Width="130"
                MinWidth="50"
                Height="130"
                MinHeight="50"
                Canvas.Top="150"
                Canvas.Left="470"
                Template="{StaticResource DesignerItemTemplate}">
        <Rectangle Fill="Blue"
           IsHitTestVisible="False"/>
    </ContentControl>


    <Canvas.Background>
        <SolidColorBrush Color="White" Opacity="0"/>
    </Canvas.Background>


</Canvas>

The control that I am trying to duplicate dynamically is this bit:

            <ContentControl  Width="130"
                MinWidth="50"
                Height="130"
                MinHeight="50"
                Canvas.Top="150"
                Canvas.Left="470"
                Template="{StaticResource DesignerItemTemplate}">
        <Rectangle Fill="Blue"
           IsHitTestVisible="False"/>
    </ContentControl>

It is the Template property that is giving me the problem - how do I create it dynamically.

What I have tried is to read in the Xaml into A XamlReader to create the control, like so:

private void CopyBlockWithXaml()
    {
        StringBuilder sb = new StringBuilder();
        sb.Append( @"<ContentControl  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'");
        sb.Append( "  Width=\"130\" MinWidth=\"50\" Height=\"130\"");
        sb.Append("        MinHeight=\"50\" ");
        sb.Append("        Canvas.Top=\"150\"");
        sb.Append("        Canvas.Left=\"470\"");
        sb.Append("        Template=\"{StaticResource DesignerItemTemplate}\">");
        sb.Append(" <Rectangle Fill=\"Blue\"");
        sb.Append("   IsHitTestVisible=\"False\"/>");
        sb.Append("</ContentControl>");
       ContentControl cc= (ContentControl) XamlReader.Parse(sb.ToString());
       LayoutRoot.Children.Add(cc);

    }

Exception:

$exception{"'Provide value on 'System.Windows.StaticResourceExtension' threw an exception.' Line number '1' and line position '258'."}  System.Exception {System.Windows.Markup.XamlParseException}

2 Answers 2

1

Dynamically creating controls by parsing Xaml at run time will work, but it is probably not the easiest approach.

Instead you could create new instances of the content control using regular C# code. Try something like this in your code behind:

var contentControl = new ContentControl 
  {
    Width = 130, 
    MinWidth = 50, 
    Height = 130, 
    MinHeight = 40 
  };

  Canvas.SetLeft(contentControl, 150);
  Canvas.SetTop(contentControl, 470);

  contentControl.Content = new Rectangle { Fill = new SolidColorBrush(Color.Blue) };

  LayoutRoot.Children.Add(contentControl);

Now this code sample probably won't compile as it is (I don't have a compiler here), but you get the idea. Just create the controls in code as you would do any other classes.

Sign up to request clarification or add additional context in comments.

2 Comments

Yes that was my first approach, but I had no idea how to set the Template property
Ah brilliant, now that I have had another go, I can see that you have given me the right answer
1

This was the code I ended up using (thanks Rune Grimstad) - it was setting the Template property that was the tricky bit for me to figure out

ContentControl cc = new ContentControl();
        ControlTemplate ct = new ControlTemplate();
        object rs = this.Resources["DesignerItemTemplate"];
        ct = (ControlTemplate)rs;
        cc.Template = ct;
        cc.Height = 10;
        cc.Width = 10;
        cc.Content = new Rectangle { Fill = new SolidColorBrush(Color.FromRgb(0,0,255)) };
        LayoutRoot.Children.Add(cc);
        Canvas.SetLeft(cc, 300);
        Canvas.SetTop(cc, 300);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.