M Miles
M Miles

Reputation: 33

Windows Phone 8.1 C#, dynamically add/remove TextBlocks to/from a Grid

I'm trying to add several seperate textblocks into a grid dynamically so that adding an element to grid will populate the next open cell.

1 2
3 4
5 6
7 8
...

and so on

When any element is removed, every element following should be shifted to fill in any empty cells so that if 2, 5, 6 are removed (one at a time) it will look like this:

1 3
4 7
8 ...

My XAML and Code are as follows:

<StackPanel x:Name="NumbersStackPanel">
                <TextBlock Text="Numbers: "/>
                <Grid x:Name="NumbersGrid">
                    <TextBox x:Name="SearchNumbers"/>
                </Grid>
            </StackPanel>

CS:

            TextBlock newTextBlock = new TextBlock();
            newTextBlock.Visibility = Windows.UI.Xaml.Visibility.Visible;
            newTextBlock.Foreground = new SolidColorBrush(Colors.Black);
            newTextBlock.FontWeight = Windows.UI.Text.FontWeights.SemiBold;
            newTextBlock.FontFamily = new Windows.UI.Xaml.Media.FontFamily("Segoe UI Semilight");
            newTextBlock.Margin = new Thickness(0, 5, 4, 0);
            newTextBlock.TextWrapping = TextWrapping.WrapWholeWords;
            newTextBlock.FontSize = 18;

            newTextBlock.Text = NumbersModelObj.Number + "; ";
            newTextBlock.Tag = NumbersModelObj.NumberId;
            textArray.Add(newTextBlock);

            NumbersGrid.Children.Insert(NumbersCount, newTextBlock);
            NumbersCount ++;

I've tried nested for loops given the value of elements (NumbersCount) but have not been successful in adding more than 2 elements to different cells into different cells in the grid

Are there any relatively simple/clean solutions for achieving this?

Upvotes: 0

Views: 282

Answers (2)

M Miles
M Miles

Reputation: 33

I've since found exactly what I was looking for here:

http://windowsapptutorials.com/windows-phone/ui/wrap-grid-with-variable-sized-items/

Hopefully this helps someone down the line.

Upvotes: 1

C. McCoy IV
C. McCoy IV

Reputation: 897

What you're looking for is a called a UniformGrid. Unfortunately, it was not ported from desktop WPF to Windows Phone WPF.

However, I did some Googling and found this:

UniformGrid.cs

using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace App1 // replace with your namespace, of course
{
    public class UniformGrid : Panel
    {
        protected override Size MeasureOverride(Size availableSize)
        {
            var itemWidth = availableSize.Width / Columns;
            foreach (FrameworkElement child in Children)
            {
                child.Measure(new Size(120, 120));
            }
            return new Size(availableSize.Width, availableSize.Width);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            Size cellSize = new Size(finalSize.Width / Columns, finalSize.Width / Columns);
            int row = 0, col = 0;
            foreach (UIElement child in Children)
            {
                child.Arrange(new Rect(new Point(cellSize.Width * col, cellSize.Height * row), cellSize));
                if (++col == Columns)
                {
                    row++;
                    col = 0;
                }
            }
            return finalSize;

        }

        public int Columns
        {
            get { return (int)GetValue(ColumnsProperty); }
            set { SetValue(ColumnsProperty, value); }
        }

        public int Rows
        {
            get { return (int)GetValue(RowsProperty); }
            set { SetValue(RowsProperty, value); }
        }

        public static readonly DependencyProperty ColumnsProperty =
    DependencyProperty.Register("Columns", typeof(int), typeof(UniformGrid), new PropertyMetadata(1, OnColumnsChanged));


        public static readonly DependencyProperty RowsProperty =
    DependencyProperty.Register("Rows", typeof(int), typeof(UniformGrid), new PropertyMetadata(1, OnRowsChanged));

        static void OnColumnsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            int cols = (int)e.NewValue;
            if (cols < 1)
                ((UniformGrid)obj).Columns = 1;
        }

        static void OnRowsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            int rows = (int)e.NewValue;
            if (rows < 1)
                ((UniformGrid)obj).Rows = 1;
        }

    }
} 

Resource: https://social.msdn.microsoft.com/Forums/windowsapps/en-US/3254c8ff-a7ad-4346-b353-457cd6ac7a58/uwpcreating-a-uniformgrid-for-listview?forum=wpdevelop

How to use it:

  1. Import UniformGrid.cs into your project; place it wherever you feel is appropriate.
  2. Update the namespace appropriately (remember this namespace for when you use it in the Xaml).
  3. Here's an example:

MainPage.xaml

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

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

        <StackPanel x:Name="NumbersStackPanel" Orientation="Vertical">
            <TextBlock Text="Numbers: "/>
            <custom:UniformGrid x:Name="NumbersGrid" Columns="2">
                <custom:UniformGrid.Resources>
                    <Style TargetType="TextBox">
                        <Setter Property="Visibility" Value="Visible" />
                        <Setter Property="Foreground" Value="Black" />
                        <Setter Property="FontWeight" Value="SemiBold" />
                        <Setter Property="FontFamily" Value="Segoe UI Semilight" />
                        <Setter Property="Margin" Value="0, 5, 4, 0" />
                        <Setter Property="TextWrapping" Value="WrapWholeWords" />
                        <Setter Property="FontSize" Value="18" />
                    </Style>
                </custom:UniformGrid.Resources>
                <TextBox Text="1" />
                <TextBox Text="2" />
                <TextBox Text="3" />
            </custom:UniformGrid>
        </StackPanel>

    </Grid>
</Page>

Note: I'd recommend doing the formatting of textboxes in XAML, as shown. The style, as implemented, targets all TextBoxes within the UniformGrid.

MainPage.xaml.cs

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace App1
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            AddText("hello");
            RemoveText("2");
            AddText("Goodbye");
            RemoveText("hello");
            RemoveText("1");
        }

        private void AddText(string text)
        {
            TextBox tb = new TextBox();
            tb.Text = text;
            NumbersGrid.Children.Add(tb);
        }

        private void RemoveText(string text)
        {
            foreach(UIElement child in NumbersGrid.Children)
            {
                TextBox tb = (TextBox)child;
                if (tb.Text.Equals(text))
                {
                    NumbersGrid.Children.Remove(tb);
                }
            }
        }

    }
}

Upvotes: 0

Related Questions