Reputation: 33
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
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
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;
}
}
}
How to use it:
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