4

Question: How can I make a Grid with a ItemsWrapGrid layout in C#?

Context

  • UWP
  • Visual Studio 2015
  • Windows 10
  • C#

Background

I know how to make it in XAML. After creating a new UWP application in Visual Studio 2015, the XAML is:

<Page
    x:Class="WrapGridTest001.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WrapGridTest001"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    MinWidth="10"
    MinHeight="10"
    >

    <Grid x:Name="thisGrid">
        <GridView x:Name="thisGridView" IsItemClickEnabled="True">
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <ItemsWrapGrid
                            x:Name="thisItemsWrapGrid"
                            Orientation="Horizontal"
                            MaximumRowsOrColumns="5"
                        />
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>
            <TextBlock Text="#1"/>
            <TextBlock Text="#2"/>
            <TextBlock Text="#3"/>
        </GridView>
    </Grid>
</Page>

To make it programmatically, I've taken it out of the XAML:

<Page
    x:Class="WrapGridTest001.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WrapGridTest001"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    MinWidth="10"
    MinHeight="10"
    >
</Page>

and tried to reproduce it in the Page's constructor:

public MainPage()
{
    this.InitializeComponent();

    // Make the Grid and set it to be the Page's .Content:
    Grid grid = new Grid();
    this.Content = grid;

    // Make the GridView for the Grid, then set it:
    GridView gridView = new GridView();
    grid.Children.Add(gridView);

    // Make the ItemsPanelTemplate; necessary?
    ItemsPanelTemplate itemsPanelTemplate = new ItemsPanelTemplate();
    gridView.ItemsPanel = itemsPanelTemplate;

    // Make the ItemsWrapGrid.  Can't figure out how to set this.
    ItemsWrapGrid itemsWrapGrid = new ItemsWrapGrid();
    // When I traced the XAML version, its ItemsWrapGrid was apparently under
    //      gridView.ItemsPanelRoot
    // , but that's a get-only property.  I can't find a place to set it.

    // Add the TextBlock's with "#1", "#2", and "#3":
    for (int i = 1; i <= 3; ++i)
    {
        TextBlock textBlock = new TextBlock();
        textBlock.Text = "#" + i.ToString();
        gridView.Items.Add(textBlock);
    }

    // All done.  However, this Grid will show contents with a vertical alignment
    // rather than a horizontal one.
}

What additional code do I need to add to set the ItemsWrapGrid in C# as it was set in the XAML? Currently the C# code creates the ItemsWrapGrid, but the ItemsWrapGrid isn't actually set anywhere since every attempt to use it so far has resulted in a bug of some sort.

Nat
  • 1,085
  • 2
  • 18
  • 35
  • You can make `ItemsPanelTemplate` as a resouce and use it in code. – tao Aug 24 '15 at 05:13
  • @tao: I can create an `ItemsPanelTemplate` easily using `var itemsPanelTempate = new ItemsPanelTemplate();`, though I'm unsure about how to set it into a `Grid` or `GridView` after producing these things programmatically in C#. – Nat Aug 24 '15 at 05:15
  • delete all that and use proper XAML and DataBinding. There's no reason to create or manipulate UI elements in procedural code in XAML based technologies. That's what XAML is for. Whatever you're trying to do, your approach is wrong. – Federico Berasategui Aug 24 '15 at 05:20
  • @ChemicalEngineer if you want to change the `Orientation` property, you can get the `ItemWrapGrid` through `(ItemsWrapGrid)gridView.ItemsPanelRoot` and then change it. – tao Aug 24 '15 at 05:23
  • @HighCore: We have an in-house app that I'm trying to port from WPF to UWP. For its GUI, it uses WPF, and whenever it has to present something, e.g. a matrix if you're doing math, then it'll generate the appropriate `Grid` with the correct number of rows and columns, then fill its elements with whatever the matrix's contents are. Is this sort of dynamic creation possible using an XAML approach? If so, I'll look into it, as long as it allows me to port the app. – Nat Aug 24 '15 at 05:27
  • @tao: Sadly the `ItemsPanelRoot` is `null` when I make the `Grid`, etc., in C#. – Nat Aug 24 '15 at 05:29
  • `Is this sort of dynamic creation possible using an XAML approach?` - I'm not 100% familiar with the UWP and I don't know for certain what limitations you will face when porting from WPF, but I have countless examples here in SO for dynamic grid-like UIs in WPF, and none of them manipulate UI elements in procedural code. See [this example](http://stackoverflow.com/a/32172197/643085) I did just today. – Federico Berasategui Aug 24 '15 at 05:31
  • [another example](http://stackoverflow.com/a/21898676/643085). – Federico Berasategui Aug 24 '15 at 05:32
  • @HighCore: Working under the assumption that your XAML expertise significantly exceeds where I could reasonably get to tonight, if you had to, could you create a GUI which dynamically generated itself from, say, user keystrokes? For example, the user types "\newMatrix[5,5]", then your GUI would recognize this and replace it with a new 5x5 `Grid` with its own lines on each of its 5x5 grid that the user could then create more `Grid`'s in by typing the same, recursively unlimited (within the computer's resources)? I ask because I thought that XAML was limited to relatively static layouts. – Nat Aug 24 '15 at 05:38
  • 1
    @ChemicalEngineer yes, you can do that. The easy part is creating the UI, the hard part is parsing the text. XAML is not limited to static layouts in any way. I recommend you read about [`ItemsControl`](http://drwpf.com/blog/itemscontrol-a-to-z/), which is the basis for all items-based UIs in WPF / XAML. – Federico Berasategui Aug 24 '15 at 05:41
  • 1
    @ChemicalEngineer call it after XAML loaded. or you can make xaml as a string and use `XamlReader` load it. – tao Aug 24 '15 at 05:42

2 Answers2

1

what you need is XamlReader

string template =
                "<ItemsPanelTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"><ItemsWrapGrid VerticalAlignment = \"Top\" "
                + " ItemWidth = \""
                + itemWidth
                + "\" Orientation = \"Horizontal\"/></ItemsPanelTemplate> ";
yourgridview.ItemsPanel = (ItemsPanelTemplate)XamlReader.Load(template);
Hunter Tran
  • 13,257
  • 2
  • 14
  • 23
1

The fact is that the ItemsWrapGrid is the default panel for the GridView. It is not nice that the ItemsPanelTemplate cannot have the ItemsWrapGrid through a property and to use the XamlReader. After the gridview is loaded it gets at ItemsPanelRoot a default ItemsWrapGrid.

yourgridview.Loaded += yourgridview_Loaded;

and the function

private void yourgridview_Loaded(object sender, RoutedEventArgs e)
{
    var a = sender as GridView;
    var b = a.ItemsPanelRoot;
    var c = b as ItemsWrapGrid;
    c.MaximumRowsOrColumns = 2;c.Orientation = Orientation.Horizontal;
}
Sam
  • 91
  • 1
  • 5