The following code gives the result that we see a divided Grid on 4 elements according to the schedule. Each column is filled with color.
<Grid Grid.Column="1" Background="#FF7E7738">
<Grid Width="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="0.6*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Background="Red"></Grid>
<Grid Grid.Column="1" Background="Green"></Grid>
<Grid Grid.Column="2" Background="Blue"></Grid>
<Grid Grid.Column="3" Background="Pink"></Grid>
</Grid>
</Grid>
Below I wrote a code that should do the same.
public ObservableCollection<Grid> ConnectorItemsGridX { get; set; }
public void DrawConnectors()
{
Grid mainGrid = new Grid();
mainGrid.Width = Double.NaN;
ColumnDefinition cd1 = new ColumnDefinition();
cd1.Width = new GridLength(1, GridUnitType.Star);
ColumnDefinition cd2 = new ColumnDefinition();
cd2.Width = new GridLength(1, GridUnitType.Star);
ColumnDefinition cd3 = new ColumnDefinition();
cd3.Width = new GridLength(0.6, GridUnitType.Star);
ColumnDefinition cd4 = new ColumnDefinition();
cd4.Width = new GridLength(1, GridUnitType.Star);
mainGrid.ColumnDefinitions.Add(cd1);
mainGrid.ColumnDefinitions.Add(cd2);
mainGrid.ColumnDefinitions.Add(cd3);
mainGrid.ColumnDefinitions.Add(cd4);
Grid tb1 = new Grid();
tb1.Background = Brushes.Beige;
Grid tb2 = new Grid();
tb2.Background = Brushes.DarkSeaGreen;
Grid tb3 = new Grid();
tb3.Background = Brushes.MistyRose;
Grid tb4 = new Grid();
tb4.Background = Brushes.Violet;
mainGrid.Children.Add(tb1);
mainGrid.Children.Add(tb2);
mainGrid.Children.Add(tb3);
mainGrid.Children.Add(tb4);
Grid.SetColumn(tb1, 0);
Grid.SetColumn(tb2, 1);
Grid.SetColumn(tb3, 2);
Grid.SetColumn(tb4, 3);
ConnectorItemsGridX = new ObservableCollection<Grid>();
ConnectorItemsGridX.Add(mainGrid);
}
Code from the XAMl file to load Grid.
<Grid Grid.Column="1" Background="#FF7E7738">
<ItemsControl ItemsSource="{Binding ConnectorItemsGridX}" HorizontalAlignment="Left">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
Why do not I see the result?
It seems to me that such a solution has a problem with downloading the width of the Grid which is higher.
If you type in a fixed value of type mainGrid.Width = 200; everything is displayed.
The window size may change more dynamically have a width equal to a grid above.
Is there anything I need to include in the code which is not used in the XAML version?
ItemsControl doesn't show Grids, because they don't have Children elements.
(Add line tb4.Children.Add(new TextBlock { Text = "100500" }); for example and you will see Violet grid).
It happens due to HorizontalAlignment="Left" and StackPanel as Items panel. Both settings arrange minimal width 0 to Grid.
this works:
<ItemsControl ItemsSource="{Binding ConnectorItemsGridX}" HorizontalAlignment="Stretch">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
I suggest to study these posts for inspiration for dynamic Grid columns:
A Simplified Grid Markup for Silverlight and WPF
by Colin Eberhardt (external)
How can I dynamically add a RowDefinition to a Grid in an ItemsPanelTemplate?
Related
I am trying to implement a button that toggles between a list and tile view of some items. The code behind is identical for both and the only difference is the size of what is displayed and the properties. Currently I have the list view implemented and the XAML looks like this:
<StackLayout>
<ListView x:Name="FilesListView"
ItemsSource="{Binding Files}"
ItemSelected="FileItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding IsFolder, Converter={StaticResource fileTypeToImageConverter}}" WidthRequest="40" HeightRequest="40" HorizontalOptions="Start"/>
<Label Grid.Column="1" Text="{Binding Path, Converter={StaticResource pathToFilenameConverter}}" HorizontalOptions="StartAndExpand"/>
<Label Grid.Column="2" Text="{Binding ModifiedDate, Converter={StaticResource dateConverter}}" HorizontalOptions="EndAndExpand"/>
<Label Grid.Column="3" Text="{Binding Size, Converter={StaticResource fileSizeConverter}}" HorizontalOptions="EndAndExpand"/>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
This is a partial view; the FileBrowser control gets nested in another stack layout that contains the toggle button. The button is defined in XAML like this:
<ContentPage.ToolbarItems>
<ToolbarItem Text="Toggle View" Order="Primary" Icon="{Binding ViewIcon}" Command="{Binding ToggleViewCommand}"/>
</ContentPage.ToolbarItems>
where ToggleViewCommand is:
protected void ToggleView()
{
FileBrowserControl.ToggleView();
ViewModel.ToggleViewIcon();
}
I need help figuring out how to implement FileBrowserControl.ToggleView();. I need to either dynamically swap out the grid XAML with a different XAML snippet (representing the tile view), or update the grid in code. The first option seems easier in terms of defining what the tile view would look like, but I don't want to duplicate the code behind logic by creating FileBrowserXaml.xaml/FileBrowserXaml.xaml.cs which would have the same code behind logic as FileBrowser.xaml.cs. What is the Xamarin best practice for what I'm trying to do?
(As a side note, this needs to be cross platform.)
Update: I decided to try to build the data template in code. I have this so far:
public void ToggleView()
{
DataTemplate itemTemplate;
if (_view == FileBrowserView.List)
{
itemTemplate = new DataTemplate(() =>
{
var cell = new ViewCell();
var grid = new Grid();
// Define columns
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
// Define rows
var image = new Image
{
WidthRequest = 40,
HeightRequest = 40,
HorizontalOptions = LayoutOptions.Start
};
image.SetBinding(Image.SourceProperty,
new Binding("IsFolder", BindingMode.Default, new FileTypeToImageValueConverter()));
grid.Children.Add(image, 0, 0);
var pathLabel = new Label {HorizontalOptions = LayoutOptions.StartAndExpand};
pathLabel.SetBinding(Label.TextProperty,
new Binding("Path", BindingMode.Default, new PathToFilenameValueConverter()));
grid.Children.Add(pathLabel, 1, 0);
var dateLabel = new Label { HorizontalOptions = LayoutOptions.StartAndExpand };
dateLabel.SetBinding(Label.TextProperty,
new Binding("ModifiedDate", BindingMode.Default, new DateTimeDisplayValueConverter()));
grid.Children.Add(dateLabel, 2, 0);
var sizeLabel = new Label { HorizontalOptions = LayoutOptions.EndAndExpand };
dateLabel.SetBinding(Label.TextProperty,
new Binding("Size", BindingMode.Default, new FileSizeDisplayValueConverter()));
grid.Children.Add(sizeLabel, 3, 0);
cell.View = grid;
return cell;
});
}
else
{
itemTemplate = new DataTemplate(() =>
{
var cell = new ViewCell();
var grid = new Grid();
// Define columns
grid.ColumnDefinitions.Add(new ColumnDefinition {Width = new GridLength(1, GridUnitType.Star)});
grid.ColumnDefinitions.Add(new ColumnDefinition {Width = new GridLength(1, GridUnitType.Star)});
// Define rows
var image = new Image
{
WidthRequest = 80,
HeightRequest = 80,
HorizontalOptions = LayoutOptions.Start
};
image.SetBinding(Image.SourceProperty,
new Binding("IsFolder", BindingMode.Default, new FileTypeToImageValueConverter()));
grid.Children.Add(image, 0, 0);
var pathLabel = new Label { HorizontalOptions = LayoutOptions.Start };
pathLabel.SetBinding(Label.TextProperty,
new Binding("Path", BindingMode.Default, new PathToFilenameValueConverter()));
grid.Children.Add(pathLabel, 0, 1);
cell.View = grid;
return cell;
});
}
FilesListView.ItemTemplate = itemTemplate;
}
The issue I am having now is, in the tile view, every item is on its own row. I want them to wrap (the path should be underneath the image, but each path/image combo should be side-by-side with the next one, like in Windows Explorer or in a typical app launcher). What is the best way to build a data template to achieve this? Is a grid the correct template to use or is there a better one?
Have you tried using the ResourceDictionary and StaticResource?
I am thinking you may be able to accomplish what you want by having the ListView ItemTemplate set to a StaticResource and then having the toggle button switch out which one is used for the view.
Below is kind of what I am thinking of:
<ContentPage>
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="TileViewTemplate">
<ViewCell>
<ViewCell.View>
<!-- the layout of your template here -->
</ViewCell.View>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="ListViewTemplate">
<ViewCell>
<ViewCell.View>
<!-- the layout of your template here -->
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
<ListView x:Name="FilesListView" ItemsSource="{Binding Files}"
ItemsSelected="FileItemSelected"
ItemTemplate="{StaticResource TileViewTemplate}"/>
</ContentPage>
And then, the toggleview command could switch the ItemTemplate property. This way you are not having to worry about two ListViews - and it can keep the XAML a bit more manageable.
Just a thought, but the ResourceDictionary has really been helpful for me.
I've got a weird problem with a listbox, which is placed in a custommessagebox.
Problem: You can't scroll down the list, because a "draggesture" up does the same thing than down. So the only thing I got is the respond-animation when your at the top of the list.
I made a little sample:
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
<TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Button Background="Bisque" Content="Click Me" Click="Button_Click"></Button>
</Grid>
</Grid>
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var source = new string[200];
for (int i = 0; i < source.Length; i++)
{
source[i] = i.ToString();
}
var dialog = new CustomMessageBox()
{
Content = new ListBox(){ItemsSource = source},
RightButtonContent = "Cancel",
LeftButtonContent = "Store",
VerticalContentAlignment = VerticalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Background = new SolidColorBrush(Colors.Black),
HorizontalContentAlignment = HorizontalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center
};
dialog.Show();
}
}
And here is the link, if you wanna download it:
https://onedrive.live.com/redir?resid=6B27FD720F1FB58D!15988&authkey=!ACG5krcfzsoBxA8&ithint=folder%2csln
Does anyone has an idea whats going wrong?
Thx for any help.
There is a simple fix for that.. Add a Height to the ListBox. Like this.
var dialog = new CustomMessageBox()
{
Content = new ListBox(){ItemsSource = source, Height = 800},
RightButtonContent = "Cancel",
LeftButtonContent = "Store",
VerticalContentAlignment = VerticalAlignment.Top, // Change to Top
VerticalAlignment = VerticalAlignment.Top, // Change to Top
Background = new SolidColorBrush(Colors.Black),
HorizontalContentAlignment = HorizontalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center
};
Change the VerticalContentAlignment and VerticalAlignment to Top so when you set the Height value less than 800 the content is aligned to the top.
just you need to add height for listbox as :
Content = new ListBox(){ItemsSource = source,Height=800}
I do not recommend setting the height, as Daniel Z mentioned you'll lose adaptive design. I managed a better workaround and it worked perfectly for me without setting the height to a static value.
Put the content of the CustomMessageBox in a UserControl. Suppose the xaml content of this control looks like this
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneBackgroundBrush}">
<!-- your listbox and content here -->
</Grid>
in the code behind, implement the loaded event:
public UserControl1()
{
InitializeComponent();
this.Loaded += UserControl1_Loaded;
}
void UserControl1_Loaded(object sender, RoutedEventArgs e)
{
LayoutRoot.Height = (this.Parent as CustomMessageBox).ActualHeight;
}
By setting the height of the grid, your listbox will automatically adjust its height to fit in. Hope it helps.
I want to binding my itemscontrol in listbox, but it doesn't work. I want to add some FrameworkElement to Listbox with stack style.
Here is my XAML code:
<ListBox x:Name="listThemes">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="5">
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Title}" FontWeight="Bold" />
<StackPanel Grid.Row="1" >
<ItemsControl Width="Auto"
Height="Auto"
ItemsSource="{Binding ElementName=listThemes, Path=Items}">
</ItemsControl>
</StackPanel>
</Grid>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I don't know how to binding ItemsControl inside ListBox. I try put out the Binding ElementName of ItemsControl but it's always crashes. If the ElementName is page name, it not work.
Testing Class :
public class Testing
{
public string Title { get; set; }
public ObservableCollection<FrameworkElement> Items { get; set; }
}
C# Code :
observableCollection = new ObservableCollection<FrameworkElement>();
for (int i = 0; i < 3; i++)
{
observableCollection.Add(new Button { Content = i.ToString() });
observableCollection.Add(new Canvas
{
Background = new ImageBrush()
{
ImageSource = new BitmapImage(new Uri(#"Assets/ApplicationIcon.png", UriKind.Relative)),
Stretch = System.Windows.Media.Stretch.Fill
},
Height = 100,
Width = 100
});
}
List<Testing> list = new List<Testing>();
for (int i = 0; i < 3; i++)
{
Testing test = new Testing();
test.Title = "Testing";
test.Items = observableCollection;
list.Add(test);
}
listThemes.ItemsSource = list;
First, it crashes because you bind the same elements on three different item. One framework element can't be attach under two different control. So you should place your ObservableCollection in your List<Testing> creating process.
Second, you should set a DataContext to your listThemes control, so its items can find the right data path to bind and then you could remove the ElementName.
Try these code.
List<Testing> list = new List<Testing>();
for (int i = 0; i < 3; i++)
{
Testing test = new Testing();
test.Title = "Testing";
var observableCollection = new ObservableCollection<FrameworkElement>();
for (int j = 0; i < 3; i++)
{
observableCollection.Add(new Button { Content = j.ToString() });
observableCollection.Add(new Canvas
{
Background = new ImageBrush()
{
ImageSource = new BitmapImage(new Uri(#"Assets/ApplicationIcon.png", UriKind.Relative)),
Stretch = System.Windows.Media.Stretch.Fill
},
Height = 100,
Width = 100
});
}
test.Items = observableCollection;
list.Add(test);
}
listThemes.DataContext = list;
listThemes.ItemsSource = list;
Third, I don't think it is a good way to bind your FrameworkElement directly to an ItemsControl. It just look weird.
Update:
If you want to generate different types of items, you can use DataTemplateSelector. Because you already parse the forum data into different type, so please check this post:
How to Control the DataTemplateSelector in Windows Store Apps
It explains how to use DataTemplateSelector to display different type of data.
Why is your inner collection of type FrameworkElement?
Create a custom type for it and set an ItemTemplate for your inner ItemsControl.
<DataTemplate x:Key=NestedItemsTemplate>
....
</DataTemplate>
<ListBox x:Name="listThemes"
ItemsSource="{Binding TestItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="5">
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Title}" FontWeight="Bold" />
<StackPanel Grid.Row="1" >
<ItemsControl
Width="Auto" Height="Auto"
ItemsSource="{Binding ElementName=listThemes, Path=Items}"
ItemTemplate="{StaticResource NestedItemsTemplate}">
</ItemsControl>
</StackPanel>
</Grid>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
I am trying to fix a larger block of code written by previous colleague - it i some sort of report system, output is a table with data. My task was to freeze column headerson top when scrolling. As i am new to this, I made very simple table, to find out how datagrid works:
public MainWindow()
{
this.InitializeComponent();
var dt = new DataTable();
dt.Columns.Add("prvni");
dt.Columns.Add("druhy");
for (int i = 0; i < 100; i++)
{
var row = dt.NewRow();
row[0] = "A" + i;
row[1] = "B" + i;
dt.Rows.Add(row);
}
this.MainGrid.ItemsSource = dt.AsDataView();
}
By lots of searching, I found many topics, which recommended to get rid of ScrollViewer, as the freezed headers are in datagrid by default. This was the original part of code I modified:
var scrollViewer = new ScrollViewer()
{
HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,
VerticalScrollBarVisibility = ScrollBarVisibility.Auto
};
scrollViewer.AddHandler(UIElement.MouseWheelEvent, new RoutedEventHandler(this.MouseWheelHandler), true);
var stackPanel = new StackPanel();
scrollViewer.Content = stackPanel;
...
return scrollViewer;
And in another function, it was used/called as:
var reportInfo = ((((sender as DataGrid).Parent as StackPanel).Parent as ScrollViewer).Parent as ReportOutputTabItem).Tag as ReportInfo;
Well - I removed the scrollviewer, and was returning it as StackPanel, however - now I cannot scroll at all. When I searched questions, how to add vertical scrolling to StackPanel, answers were "add ScrollViewer".
So - is there a way, how either make column headers freezed inside the ScrollViewer, or how to enable vertical scrolling in StackPanel without using scrollViewer? (and another possible solution might be to make the vertical size of StackPanel bit shorter, as there are mostly pages of results, but full page is still required to scroll a bit).
XAML part:
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TabControl Name="MainTab" SelectionChanged="MainTabSelectionChanged" ItemTemplate="{StaticResource ClosableTabItemTemplate}"/>
<StackPanel Grid.Row="1" Name="NavigationPanel" Orientation="Horizontal" HorizontalAlignment="Center">
<Button Height="23" Name="FirstButton" Width="40" Content="<<" Click="PageButtonClick" Opacity="0.75"/>
<Button Height="23" Name="PrevButton" Width="40" Click="PageButtonClick" Opacity="0.75" Content="<"/>
<Label Height="23" Name="PageNumberLabel" Width="70" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Content="1/1"/>
<Button Height="23" Name="NextButton" Width="40" Content=">" Click="PageButtonClick" Opacity="0.75"/>
<Button Height="23" Name="LastButton" Width="40" Click="PageButtonClick" Opacity="0.75" Content=">>"/>
</StackPanel>
Thanks in advance.
Well, I finally found solution to this:
Originally, the datagrid was wrapped in the StackPanel, and then in ScrollViewer. I removed the ScrollViewer, and replaces StackPanel with Grid.
Now I have both vertical scrollbars, and frozen column headers.
I removed the entire
var scrollViewer = new ScrollViewer()
{
HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,
VerticalScrollBarVisibility = ScrollBarVisibility.Auto
};
scrollViewer.AddHandler(UIElement.MouseWheelEvent, new RoutedEventHandler(this.MouseWheelHandler), true);
var stackPanel = new StackPanel();
scrollViewer.Content = stackPanel;
and replaced with simple var grid = new Grid();
and all stackPanel.Children.Add(dataGrid); replaced with grid.Children.Add(dataGrid);
I implemented some cpu scheduling algorithm.and i want to show it in windows form application in c# graphically but i don't know how?
example:
I have these processes:
p1,p2,p3,p4,p5,p6,p7,p8,p9,...
p2 do its process before p1,and p1 before p6 and p6 before p3 and...
I want something like this to show it for me:
http://i.stack.imgur.com/zEWbG.jpg
also each process length change based on its own process time, and show process start time and end time too.
How can I make something like that?
thank u.
I would recommend using WPF. You could achieve this many different ways.
One example is a WPF Grid with multiple columns. You can set the width of the column as a proportion. Eg A width of "3*" would indicate a process that takes half the time as a width of "6*"
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid Name="MainGrid" Height="80">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="2*"></ColumnDefinition>
<ColumnDefinition Width="4*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Rectangle Fill="LightBlue"/>
<Rectangle Grid.Column="1" Fill="LightGreen"/>
<Rectangle Grid.Column="2" Fill="LightPink"/>
<Label HorizontalAlignment="Center" VerticalAlignment="Center">P2</Label>
<Label Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center">P1</Label>
<Label Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center">P6</Label>
</Grid>
</Window>
This XAML code would produce this.
http://img835.imageshack.us/img835/4742/picturelx.png
You could programatically add columns using C# code-behind like this.
private void AddColumn()
{
//Create the columndefinition with a width of "3*"
ColumnDefinition column = new ColumnDefinition();
column.Width = new GridLength(3, GridUnitType.Star);
//Add the column to the grid
MainGrid.ColumnDefinitions.Add(column);
//Create the rectangle
Rectangle rect = new Rectangle();
rect.Fill = new SolidColorBrush(Colors.Beige);
MainGrid.Children.Add(rect);
Grid.SetColumn(rect, 3);
//Create the label
Label label = new Label();
label.VerticalAlignment = System.Windows.VerticalAlignment.Center;
label.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
label.Content = "P4";
MainGrid.Children.Add(label);
Grid.SetColumn(label, 3);
}