6

Question: I am new to WPF and i am not able to figure out this. How do i create a grid with x rows and y columns and insert image into each cell at run time ?

Scenario: I have an inventory project where the end user will search for a item and the application will specify where he can find the item. Now i am already retrieving the cabinet details where the items are kept which again have a rack of x rows and y columns . The rack being displayed can have different row or column sizes.See Image.

Approach: So what i figured out is that i should have a grid of x rows and y columns (known only at run time). Fill an image for each cell value. Insert a different image into the location of the item or highlight that cell value. But i am not able to find how to do that. Most of my searches point to add rows and columns dynamically. Am i missing something very obvious?

Expected Output: Given below is how i would like it to be displayed to my end user : Preview

Community
  • 1
  • 1
simba
  • 463
  • 3
  • 6
  • 17
  • Is the size of the table fixed? – Nzc Nov 21 '13 at 08:29
  • No. Different racks have different number of rows and columns. So once the user searches we identify which cabinet and rack it is. Then create a table(grid) with rows X columns of the rack we found out. After this point it will just be a static display. – simba Nov 21 '13 at 08:32
  • 2
    You could take a look [here](http://rachel53461.wordpress.com/2011/09/17/wpf-grids-rowcolumn-count-properties/). It allows you to bind the row/column count and has code samples. –  Nov 21 '13 at 08:40
  • @DamenEU: Let me try that. Looks like what i might need. – simba Nov 21 '13 at 08:53
  • possible duplicate of [How to populate a WPF grid based on a 2-dimensional array](http://stackoverflow.com/questions/276808/how-to-populate-a-wpf-grid-based-on-a-2-dimensional-array) – Martin Liversage Nov 21 '13 at 10:06
  • possible duplicate of [wpf grid with dynamic columns](http://stackoverflow.com/questions/13814224/wpf-grid-with-dynamic-columns) – Meirion Hughes Nov 21 '13 at 11:26

3 Answers3

3

Like i said i was always wondering whether we need to go for a data grid in cases where we have static data. So this is what i came up with. I create a stack panel and add y images. Now i add x such stack panels. If the exact location of the image comes up i add a highlighted image. worked perfectly. Sharing code for any one who wants to reuse it.

private void CreateGraphicalDisplay(int rows,int columns,int row,int column)
    {
        ClearGraphicPanel();
        for (int i = 1; i <= rows; i++)
        {

        StackPanel childstack = new StackPanel();


            for (int j = 1; j <= columns; j++)
            {
                Image gage = new Image();
                gage.Stretch = Stretch.Fill;

                if (i == row && j == column)
                {
                    gage.Source = new BitmapImage(new Uri(@Highlightedimage));
                }
                else
                {
                    gage.Source = new BitmapImage(new Uri(@NormalImage));
                }
                gage.Width = 12;
                gage.Height =12;
                gage.HorizontalAlignment = HorizontalAlignment.Left;
                gage.Margin = new Thickness(10, 1, 1, 1);

                childstack.Children.Add(gage);
            }

            containerstack.Children.Add(childstack);
        }

    }
simba
  • 463
  • 3
  • 6
  • 17
  • I think this is a different approach from what is normally suggested. So please feel to give your opinion. This gives me exactly the grid structure i asked for. – simba Dec 02 '13 at 08:44
2

you can try come thing like this

Xmal

  <Grid>
    <ItemsControl ItemsSource="{Binding A}" >
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal" >
                    <Label Content="{Binding Heading}" BorderThickness="2, 0, 2, 2" BorderBrush="Black"/>
                    <ItemsControl ItemsSource="{Binding Values}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Horizontal"/>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <Label Content="{Binding}" BorderThickness="0, 0, 2, 2" BorderBrush="Black"/>

                                </StackPanel>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

View Model

class ViewModel
{
    public List<Inventory> A
    {
        get;
        set;
    }

    public ViewModel()
    {
        A = new List<Inventory>();

        for (int i = 1; i <10; i++)
        {
            Inventory iv = new Inventory();
            iv.Heading = "R" + i ;
            iv.Values = new List<string>();
            for (int j = 0; j < 5; j++)
            {
                iv.Values.Add("Pic");
            }
            A.Add(iv);
        }
    }
}

public class Inventory
{
    public string Heading
    {
        get;
        set;
    }

    public List<string> Values
    {
        get;
        set;
    }
}
Rachel
  • 130,264
  • 66
  • 304
  • 490
Kumareshan
  • 1,311
  • 8
  • 8
0

You can use a standard DataGrid to do that. You can find out how to use one on the DataGrid Class page on MSDN. Normally when using these controls, you would Bind a collection of a custom data type class instances to the DataGrid.ItemsSource property and the DataGrid would add a row for every item in the collection and a column for every property in the data type class.

As you want to have a variable number of columns, that would cause you a problem. However, there are something in .NET called Anonymous Types that you can use. This basically enables you to define an anonymous class at run time, so that you can define as many properties as you need columns. You can find out how to use them in the Anonymous Types (C# Programming Guide) page on MSDN.

My last hint for you is that you'd want to have string properties in your anonymous classes that provide the relevant image paths to use to display whatever image you want in each column. Then, you can declare a DataTemplate to define what each cell should look like (an Image)... for this to work, your string file paths will need to be in the following format -/YourAppName;component/YourImageFolderName/YourImageName.jpg:

<DataGrid ItemsSource="{Binding YourAnonymousTypedCollection}">
    <DataGrid.ItemTemplate>
        <DataTemplate>
            <Image Source="{Binding}" />
        </DataTemplate>
    </DataGrid.ItemTemplate>
</DataGrid>

You can find out more from the ItemsControl.ItemTemplate Property and Data Templating Overview pages on MSDN.

Just in case that wasn't clear to anyone, I also added the link to the Anonymous Types (C# Programming Guide) page on MSDN, so that anyone that didn't understand could find out the whole story. Therefore, your first comment was unnecessary and helped nobody.

Moving on to your remarkable second comment where you flat out tell me that I will not be able to solve the "dynamic columns" problem using an anonymous class... this time you are just plain incorrect. You really should check these things before you make such claims. To prove that my method works, I knocked up a quick and easy example:

Here is a DataGrid:

<DataGrid Name="DataGrid" AutoGenerateColumns="True" />

Here's where I define my anonymous type, put them in a List and Bind them to the DataGrid:

var item = new { Id = 1, Name = "Bob", Age = 30 };
var item2 = new { Id = 2, Name = "Jane", Age = 26 };
var item3 = new { Id = 3, Name = "Dave", Age = 42 };
var items = new[] { item, item2, item3 }.ToList();
DataGrid.ItemsSource = items;

You can then see that it works perfectly well. Extending this example by creating a type with a different number of parameters shows that it would work with any number of columns:

var item = new { Id = 1, Name = "Bob", Age = 30, Date = DateTime.Now };
var item2 = new { Id = 2, Name = "Jane", Age = 26, Date = DateTime.Now };
var item3 = new { Id = 3, Name = "Dave", Age = 42, Date = DateTime.Now };
var items = new[] { item, item2, item3 }.ToList();
DataGrid.ItemsSource = items;

Of course the question author could declare the items in a loop to make it more efficient.

user229044
  • 232,980
  • 40
  • 330
  • 338
Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • Anonymous types are not created at run time but are simply syntactic sugar where the compiler creates a type for you. To create a type at run time you either need to compile it on the fly or use something like `dynamic`. – Martin Liversage Nov 21 '13 at 09:56
  • 2
    @Martin, was it *really* worth nit picking this tiny difference in the language used when I was trying to explain some complex programming concepts in the simplest terms to a beginner? In my opinion, it wasn't, as the question author is none the wiser after your comment. Furthermore, I added a link so that they could find out *all* about using anonymous types from Microsoft, so *your* 'help' was really not required here, but thanks. – Sheridan Nov 21 '13 at 10:13
  • I am sorry if you find my comment "nitpicking", but your statement that you can define an anonymous class at run time is incorrect. And while your suggestion to use a `DataGrid` is sensible you will not be able to solve the "dynamic columns" problem using an anonymous class. Beginner or not, anonymous classes are not useful when creating a dynamic grid. Or perhaps you can provide a more elaborate demonstration on how to do it in case I have overlooked something? – Martin Liversage Nov 21 '13 at 10:47
  • 1
    Sorry @MartinLiversage, but it is *you* that is incorrect. Please see my updated answer for the simplest of examples that contradicts *your* statement. – Sheridan Nov 21 '13 at 11:23
  • 1
    @Sheridan: I think i will run into an issue here because i will need to dynamically add properties at run time.In this case i know i have x rows and y columns. So i have to add y properties into each var item.So even with a loop how can i add y properties to a var object at run time? I will follow up with a similar logic to yours that i am working on. – simba Nov 23 '13 at 17:36
  • @Sheridian: I wrote my own code snippet that gave me the solution. I more or less derived it from your concept of adding y properties. Instead i added y images and x stack panels. Please let me know of your opinion on this solution – simba Dec 02 '13 at 08:47