none
Bind a Grid to a Changing Canvas

    คำถาม

  • I would like to bind my grid to the canvas which it is now but when I change the canvas size with the text boxes the canvas grid does not change size. What am I missing. I did try running it with the binding in the text changed event for the textboxes but that did not seem to work either. I could code it but I would rather use a binding if possible.

    <Window x:Class="DynamicGridBinding.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:DynamicGridBinding"
    	x:Name="mainWindow"
    	Title="MainWindow" Height="350" Width="525">
        <Grid>
           <Border Width="{Binding ElementName=textBoxWidth, Path=Text}"  Height="{Binding ElementName=textBoxHeight, Path=Text}" BorderBrush="Black" BorderThickness="2" CornerRadius="1" Grid.Column="1" >    
            <Canvas x:Name="canvasDrawing"  Background="#FFF3F7F6" SnapsToDevicePixels="True" ClipToBounds="True">
                    <!-- Bind the ItemsControl to Main -->
                    <ItemsControl  ItemsSource="{Binding GridList}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <!-- Make a canvas the ItemsPanelTemplate so you have something to draw to -->
                                <Canvas Width="{Binding Text, ElementName=textBoxWidth}" Height="{Binding Text, ElementName=textBoxHeight}"/>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <!-- Bind the data template to x1 x2 y1 y2 stroke created in the code -->
                                <Line X1="{Binding X1}" X2="{Binding X2}" Y1="{Binding Y1}" Y2="{Binding Y2}" Stroke="{Binding Stroke}" StrokeThickness="1" Opacity="0.25" />
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </Canvas>
            </Border>
            <Label Content="Canvas Width:" Height="27" HorizontalAlignment="Left" Margin="78,18,0,0" Name="label1" VerticalAlignment="Top" Width="85" />
            <Label Content="Canvas Height:" Height="31" HorizontalAlignment="Left" Margin="78,61,0,0" Name="label2" VerticalAlignment="Top" Width="85" />
            <TextBox Height="30" HorizontalAlignment="Left" Margin="174,21,0,0" Name="textBoxWidth" VerticalAlignment="Top" Width="85" Text="50" />
            <TextBox Height="28" HorizontalAlignment="Left" Margin="174,65,0,0" Name="textBoxHeight" VerticalAlignment="Top" Width="84" Text="50" />
        </Grid>
    </Window>
    

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace DynamicGridBinding
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
      
        public partial class MainWindow : Window
        {
            //this list will contain all the lines for the grid of the canvas
            private List<object> gridList = new List<object>();
            
            public List<object> GridList
            {
                get { return gridList; }
                set { gridList = value; }
            }
            
            
            
            public MainWindow()
            {
                InitializeComponent();
                DrawGrid();
                //This code is for binding
                mainWindow = this;
                //he makes the list the data context of the main window
                this.DataContext = this;
            }
            private void DrawGrid()
            {
                
                //This is a XAML Grid XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 
                //he adds the columns
                string placeHolderWidth = "50";
                if (textBoxWidth.Text != null) placeHolderWidth = textBoxWidth.Text;
                string placeHolderHeight = "50";
                if (textBoxHeight.Text != null) placeHolderHeight = textBoxHeight.Text;
    
                for (int i = 10; i < Convert.ToInt16(placeHolderWidth); i = i + 10)              //Convert.ToInt16(textBoxWidth.Text); i = i + 10)
                    //he uses an annonomous method to create the values
                    gridList.Add(new { Stroke = Brushes.Blue, X1 = i, X2 = i, Y1 = 0, Y2 = Convert.ToInt16(placeHolderWidth) });
                //he adds the rows
                for (int i = 10; i < Convert.ToInt16(placeHolderHeight); i = i + 10)                           //Convert.ToInt16(textBoxHeight.Text); i = i + 10)
                    gridList.Add(new { Stroke = Brushes.Red, X1 = 0, X2 = Convert.ToInt16(placeHolderHeight), Y1 = i, Y2 = i });
                 
            }
        }
    }


    Mike Gallinger C.Tech. Cutting Edge Computing Software Developer

    17 มีนาคม 2555 3:06

คำตอบ

  • > I would like to bind my grid to the canvas  
     
     
    there is another approach. instead of lines you can create a background for the canvas.
    below is an example. 
     
    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                canvasDrawing.Background = CreateGrid(25, 25, Brushes.Navy, Brushes.Blue);
            }
    
            public static ImageBrush CreateGrid(int width, int height, Brush vb, Brush hb, double thickness=.5)
            {
                var ret = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Default);
                var dv = new DrawingVisual();
                using (var dc = dv.RenderOpen())
                {
                    dc.DrawLine(new Pen(vb, thickness), new Point(width, 0), new Point(width, height));   // vertical line
                    dc.DrawLine(new Pen(hb, thickness), new Point(0, height), new Point(width, height));    // horizontal line
                }
                ret.Render(dv);
                return new ImageBrush(ret)
                {
                    TileMode = TileMode.Tile,
                    ViewportUnits = BrushMappingMode.Absolute,
                    Stretch = Stretch.None,
                    AlignmentX = AlignmentX.Left,
                    AlignmentY = AlignmentY.Top,
                    Viewport = new Rect(0, 0, width, height)
                };
            }
        }
    }
    <Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="700" Width="700">
        <StackPanel>
            <TextBox Name="tbWidth" Text="450" Width="100" />
            <TextBox Name="tbHeight" Text="450" Width="100" />
            <Border Width="{Binding Text, ElementName=tbWidth}" Height="{Binding Text, ElementName=tbHeight}" 
                BorderBrush="Black" BorderThickness="1" Margin="0,20,0,0">
                <Canvas x:Name="canvasDrawing" SnapsToDevicePixels="True" ClipToBounds="True" />
            </Border>
        </StackPanel>
    </Window>
       
         
    • ทำเครื่องหมายเป็นคำตอบโดย Mike_CuttingEdge 19 มีนาคม 2555 1:53
    18 มีนาคม 2555 17:36

ตอบทั้งหมด

  • > when I change the canvas size with the text boxes the canvas grid does not change size.
     
     
    try using the following code. 
      
     

    using System.Collections;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Media;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public IEnumerable GridList { get; private set; }
    
            public MainWindow()
            {
                InitializeComponent();
                this.GridList = new BindingList<object> 
                {
                    new { X1 = 0, Y1 = 0, X2 = 100, Y2 = 100, Stroke=Brushes.Red },
                    new { X1 = 100, Y1 = 0, X2 = 200, Y2 = 200, Stroke=Brushes.Navy },
                };
                this.DataContext = this;
            }
        }
    }
    
    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="700" Width="700">
        <StackPanel>
            <TextBox x:Name="textBoxWidth" Text="500" />
            <TextBox x:Name="textBoxHeight" Text="500" />
            <Grid>
                <ItemsControl ItemsSource="{Binding GridList}" Width="{Binding Text, ElementName=textBoxWidth}" Height="{Binding Text, ElementName=textBoxHeight}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <Canvas Background="WhiteSmoke" />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Line X1="{Binding X1}" X2="{Binding X2}" Y1="{Binding Y1}" Y2="{Binding Y2}" Stroke="{Binding Stroke}" />
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </Grid>
        </StackPanel>
    </Window>
    

      
       

    17 มีนาคม 2555 4:53
  • Hi: Your example just draws 2 lines with no grid and no resizing.

    Mike Gallinger C.Tech. Cutting Edge Computing Software Developer

    17 มีนาคม 2555 15:10
  • > Your example just draws 2 lines with no grid and no resizing.
     
     
    you can add additional items to the this.GridList defined in the MainWindow.
     
        
    17 มีนาคม 2555 15:56
  • Try this:

    XAML:

    <Window x:Class="WpfApplication7.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication7"
            x:Name="mainWindow"
            Title="MainWindow" Height="350" Width="700">
      <Grid>
        <Border Width="{Binding ElementName=textBoxWidth, Path=Text}"  Height="{Binding ElementName=textBoxHeight, Path=Text}" BorderBrush="Black" BorderThickness="2" CornerRadius="1" Grid.Column="1" >
          <Canvas x:Name="canvasDrawing"  Background="#FFF3F7F6" SnapsToDevicePixels="True" ClipToBounds="True">
            <!-- Bind the ItemsControl to Main -->
            <ItemsControl  ItemsSource="{Binding GridList}">
              <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                  <!-- Make a canvas the ItemsPanelTemplate so you have something to draw to -->
                  <Canvas Width="{Binding Text, ElementName=textBoxWidth}" Height="{Binding Text, ElementName=textBoxHeight}" SizeChanged="Canvas_SizeChanged" />
                </ItemsPanelTemplate>
              </ItemsControl.ItemsPanel>
              <ItemsControl.ItemTemplate>
                <DataTemplate>
                  <!-- Bind the data template to x1 x2 y1 y2 stroke created in the code -->
                  <Line X1="{Binding X1}" X2="{Binding X2}" Y1="{Binding Y1}" Y2="{Binding Y2}" Stroke="{Binding Stroke}" StrokeThickness="1" Opacity="0.25" />
                </DataTemplate>
              </ItemsControl.ItemTemplate>
            </ItemsControl>
          </Canvas>
        </Border>
        <Label Content="Canvas Width:" Height="27" HorizontalAlignment="Left" Margin="78,18,0,0" Name="label1" VerticalAlignment="Top" Width="85" />
        <Label Content="Canvas Height:" Height="31" HorizontalAlignment="Left" Margin="78,61,0,0" Name="label2" VerticalAlignment="Top" Width="85" />
        <TextBox Height="30" HorizontalAlignment="Left" Margin="174,21,0,0" Name="textBoxWidth" VerticalAlignment="Top" Width="85" Text="50" />
        <TextBox Height="28" HorizontalAlignment="Left" Margin="174,65,0,0" Name="textBoxHeight" VerticalAlignment="Top" Width="84" Text="50" />
      </Grid>
    </Window>
    

    C#

    using System;
    using System.Collections.ObjectModel;
    using System.Windows;
    using System.Windows.Media;
    
    namespace WpfApplication7
      {
      public partial class MainWindow : Window
        {
        //this list will contain all the lines for the grid of the canvas
        private ObservableCollection<object> gridList = new ObservableCollection<object>();
    
        public ObservableCollection<object> GridList
          {
          get { return gridList; }
          set { gridList = value; }
          }
    
        public MainWindow()
          {
          InitializeComponent();
          //mainWindow = this; (don't do this, it's already set)
          //he makes the list the data context of the main window
          this.DataContext = this;
          textBoxHeight.Text = "50";
          textBoxWidth.Text = "50";
          }
    
        private void DrawGrid()
          {
          //This is a XAML Grid XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 
          string placeHolderWidth = textBoxWidth.Text;
          string placeHolderHeight = textBoxHeight.Text;
          //he adds the columns
          for (int i = 10; i < Convert.ToInt16(placeHolderWidth); i = i + 10)            
            //he uses an annonomous method to create the values
            gridList.Add(new { Stroke = Brushes.Blue, X1 = i, X2 = i, Y1 = 0, Y2 = Convert.ToInt16(placeHolderHeight) });
          //he adds the rows
          for (int i = 10; i < Convert.ToInt16(placeHolderHeight); i = i + 10)           
            gridList.Add(new { Stroke = Brushes.Red, X1 = 0, X2 = Convert.ToInt16(placeHolderWidth), Y1 = i, Y2 = i });
          }
    
        private void Canvas_SizeChanged(object sender, SizeChangedEventArgs e)
          {
          gridList.Clear();
          DrawGrid();
          }
    
        }
      }
    


    John Fenton, MCC
    Wordmasters Direct Mail and Data Processing Services

    17 มีนาคม 2555 16:28
  • I would like to bind my grid to the canvas which it is now but when I change the canvas size with the text boxes the canvas grid does not change size. What am I missing. I did try running it with the binding in the text changed event for the textboxes but that did not seem to work either. I could code it but I would rather use a binding if possible.

    BTW, Since your grid has a fixed 10x10 cell width, the number of items in your items control needs to change based on the size of the canvas.

    I don't know of a way to do that with binding alone.

    If what you actually wanted was the cell count to stay the same and the size of the cells to shrink and grow with the canvas.  I would dump the items control altogether, create the lines in XAML and use converters on the bindings to adjust the positions of the lines.


    John Fenton, MCC
    Wordmasters Direct Mail and Data Processing Services

    17 มีนาคม 2555 20:09
  • > I would like to bind my grid to the canvas  
     
     
    there is another approach. instead of lines you can create a background for the canvas.
    below is an example. 
     
    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                canvasDrawing.Background = CreateGrid(25, 25, Brushes.Navy, Brushes.Blue);
            }
    
            public static ImageBrush CreateGrid(int width, int height, Brush vb, Brush hb, double thickness=.5)
            {
                var ret = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Default);
                var dv = new DrawingVisual();
                using (var dc = dv.RenderOpen())
                {
                    dc.DrawLine(new Pen(vb, thickness), new Point(width, 0), new Point(width, height));   // vertical line
                    dc.DrawLine(new Pen(hb, thickness), new Point(0, height), new Point(width, height));    // horizontal line
                }
                ret.Render(dv);
                return new ImageBrush(ret)
                {
                    TileMode = TileMode.Tile,
                    ViewportUnits = BrushMappingMode.Absolute,
                    Stretch = Stretch.None,
                    AlignmentX = AlignmentX.Left,
                    AlignmentY = AlignmentY.Top,
                    Viewport = new Rect(0, 0, width, height)
                };
            }
        }
    }
    <Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="700" Width="700">
        <StackPanel>
            <TextBox Name="tbWidth" Text="450" Width="100" />
            <TextBox Name="tbHeight" Text="450" Width="100" />
            <Border Width="{Binding Text, ElementName=tbWidth}" Height="{Binding Text, ElementName=tbHeight}" 
                BorderBrush="Black" BorderThickness="1" Margin="0,20,0,0">
                <Canvas x:Name="canvasDrawing" SnapsToDevicePixels="True" ClipToBounds="True" />
            </Border>
        </StackPanel>
    </Window>
       
         
    • ทำเครื่องหมายเป็นคำตอบโดย Mike_CuttingEdge 19 มีนาคม 2555 1:53
    18 มีนาคม 2555 17:36
  • > I would like to bind my grid to the canvas  
     
    there is another approach. instead of lines you can create a background for the canvas.
    below is an example.      
    Nice solution!!!

    John Fenton, MCC2011
    Wordmasters Direct Mail and Data Processing Services

    19 มีนาคม 2555 1:33
  • Hi Malobukv & John: Thanks for the replies & help. Perfect solution Malobukv!! Thanks indeed.

    Mike.


    Mike Gallinger C.Tech. Cutting Edge Computing Software Developer

    19 มีนาคม 2555 1:53