I want to remove the default margins in microcharts and stretch the graphic to the end of the frame using xamarin.
My xaml code is:
<Frame
BorderColor="White"
Margin="10,0,10,0"
CornerRadius="10"
HasShadow="True"
BackgroundColor="Transparent">
<StackLayout>
<forms:ChartView x:Name="Chart1"
HeightRequest="150"
HorizontalOptions="FillAndExpand"/>
</StackLayout>
</Frame>
My c# code is:
List<EntryMicrocharts> entries = new List<EntryMicrocharts>
{
new EntryMicrocharts ((float)TemperaturesList[0].AvgTemperature)
{
Color=SKColor.Parse("#ffffff"),
Label = Info1Forecast,
ValueLabel = Math.Round((float)TemperaturesList[0].AvgTemperature,0).ToString() + "°C",
ValueLabelColor = SKColor.Parse("#ffffff")
},....... more same code here
};
Chart1.Chart = new LineChart()
{
Entries = entries,
PointSize = 30,
LineSize = 12,
LabelTextSize = 35f,
LabelOrientation = Orientation.Horizontal,
ValueLabelOrientation = Orientation.Horizontal,
BackgroundColor = SKColors.Transparent,
LabelColor = SKColor.Parse("#ffffff"),
};
}
}
How to stretch the graphic to the end of the frame ?
I try with Margin = "0,0,0,0" in xaml code but this not work for me.
Is there a way to remove margins ?
This is a known issue with width of LineChart. You can either fix this bug in MicroCharts or try changing to another type of charts if that works for you, like BarChart:
Chart1.Chart = new BarChart()
{
Entries = entries,
LabelTextSize = 35f,
LabelOrientation = Orientation.Horizontal,
ValueLabelOrientation = Orientation.Horizontal,
BackgroundColor = SKColors.Transparent,
LabelColor = SKColor.Parse("#FFFFFF")
};
Also, add appropriate padding in XAML, like Padding = "2".
Related
My code creates the grid just like I want to, but my issue is the formatting of it. For example, the below syntax has the grid (using iPhone emulator) start at almost the half-way point of the screen. From best of I can tell, I am only declaring the width of the date column as I do not want it to be drug onto 2 lines if it is a 2 digit month or 2 digit year.
What would be the best way to alter this code so that the grid will span the entire screen in Up & Down format, not Horizontal.
private void LoadInvoiceGrid()
{
List<InvoiceHistory> IH = new List<InvoiceHistory>();
IH = dal.GetInvoices(company);
Grid usergrid = new Grid();
//Adding in this line makes no diff to the display of the grid
usergrid.VerticalOptions = LayoutOptions.FillAndExpand;
//
usergrid.Padding = new Thickness(10, 120, 0, 0);
usergrid.RowDefinitions.Add(new RowDefinition { Height = 50 });
foreach (var item in IH)
usergrid.RowDefinitions.Add(new RowDefinition { Height = 50 });
usergrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star });
usergrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star });
usergrid.ColumnDefinitions.Add(new ColumnDefinition { Width = 50 });
Label invoicenumHeader = new Label
{
Text = "Invoice #"
};
Label invoiceamountHeader = new Label
{
Text = "Amount"
};
Label invoiceduedateHeader = new Label
{
Text = "Due Date"
};
Grid.SetColumn(invoicenumHeader, 1);
Grid.SetColumn(invoiceamountHeader, 2);
Grid.SetColumn(invoiceduedateHeader, 3);
usergrid.Children.Add(invoicenumHeader);
usergrid.Children.Add(invoiceamountHeader);
usergrid.Children.Add(invoiceduedateHeader);
int rowIndex = 1;
foreach (var item in IH)
{
string date = item.invoiceduedate.Date.ToShortDateString();
Label invoicenum = new Label
{
Text = item.invoicenum.ToString()
};
Label invoiceamount = new Label
{
Text = "$" + item.invoiceamt.ToString("0.##")
};
Label invoiceduedate = new Label
{
Text = date
};
Grid.SetRow(invoicenum, rowIndex);
Grid.SetRow(invoiceamount, rowIndex);
Grid.SetRow(invoiceduedate, rowIndex);
Grid.SetColumn(invoicenum, 1);
Grid.SetColumn(invoiceamount, 2);
Grid.SetColumn(invoiceduedate, 3);
usergrid.Children.Add(invoicenum);
usergrid.Children.Add(invoiceamount);
usergrid.Children.Add(invoiceduedate);
rowIndex++;
}
InvoiceGrid = usergrid;
}
EDIT
In my XAML I have the Vertical Option set to Fill And Expand and it is not making any difference. See my XAML for the page.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Pages.DoIt" >
<ContentPage.Content>
<StackLayout Orientation="Vertical" Padding="30" Spacing="40">
<Label TextColor="#77d065" FontSize = "8" Text="Yes, Test, Text" />
<Label TextColor="Blue" FontSize="8" Text="{Binding CompanyWelcomeMessage}" />
<ContentView VerticalOptions="FillAndExpand" Content="{Binding InvoiceGrid,Mode=TwoWay}" Padding="0,10,0,0"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
I have tried to make a page in my app where all controls are generated dynamically via C# code behind. I am using a Nuget Packages, DLToolkit, flowlist to create a flow list.
I have already used this package in my project before using Xaml, and it fully works.
However when I try to create a datatemplate in code behind, it just displays a blank control, however when hovering above this control, you can see there's actually items in it.
My question is: How can I make a datatemplate with databindings in code behind?
Here is an example and works in Xaml:
<flv:FlowListView x:Name="flvList" BackgroundColor="White" FlowColumnCount="3" FlowItemsSource="{Binding LstItemSource}" HasUnevenRows="True">
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<StackLayout BackgroundColor="White" Padding="2" HorizontalOptions="FillAndExpand">
<Frame Margin="20" Padding="0" HeightRequest="175" OutlineColor="Gray" BackgroundColor="White" CornerRadius="10" HasShadow="True" IsClippedToBounds="True">
<Frame.Content>
<AbsoluteLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
<Image Aspect="AspectFill" AbsoluteLayout.LayoutBounds="1,1,1,1" AbsoluteLayout.LayoutFlags="All" Source="{Binding BgImage}" />
<BoxView Color="Black" Opacity=".5" AbsoluteLayout.LayoutBounds="1,1,1,1" AbsoluteLayout.LayoutFlags="All"/>
<StackLayout Margin="20" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<Label Text="{Binding SubTitle}" FontSize="Medium" TextColor="#66FFFFFF"/>
<Label Text="{ Binding Title}" FontSize="Large" TextColor="White" />
</StackLayout>
</AbsoluteLayout>
</Frame.Content>
</Frame>
</StackLayout>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>
However, in this project the controls are generated, so there is no Xaml code involved.
This is an example of the code that I've tried in code behind, but doesn't work:
#region Datatemplate
var dataTemplate = new DataTemplate(() =>
{
var StackLayout = new StackLayout { BackgroundColor = Color.Pink, Padding = 2, HorizontalOptions = LayoutOptions.FillAndExpand };
#region children/content for frame
AbsoluteLayout absoluteLayout = new AbsoluteLayout { HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.FillAndExpand };
#region content for AbsoluteLayout
var imgBg = new Image();
AbsoluteLayout.SetLayoutBounds(imgBg , new Rectangle(1, 1, 1, 1));
AbsoluteLayout.SetLayoutFlags(imgBg , AbsoluteLayoutFlags.All);
imgBg .SetBinding(Image.SourceProperty, "BgImage");
absoluteLayout.Children.Add(imgBg );
var overlayBox = new BoxView { Color = Color.Black, Opacity = 0.5 };
AbsoluteLayout.SetLayoutBounds(overlayBox, new Rectangle(1, 1, 1, 1));
AbsoluteLayout.SetLayoutFlags(overlayBox, AbsoluteLayoutFlags.All);
absoluteLayout.Children.Add(overlayBox);
#region InnerStackpanel
StackLayout innerStackVoorAbsoluteLayout = new StackLayout { Margin = new Thickness(20), VerticalOptions = LayoutOptions.CenterAndExpand, HorizontalOptions = LayoutOptions.CenterAndExpand };
var lblTitel = new Label { FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)), TextColor = Color.White };
var lblSubTitel = new Label { FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)), TextColor = Color.White };
//Bindings
lblTitel.SetBinding(Label.TextProperty, "Title");
lblSubTitel.SetBinding(Label.TextProperty, "SubTitle");
innerStackVoorAbsoluteLayout.Children.Add(lblSubTitel);
innerStackVoorAbsoluteLayout.Children.Add(lblTitel);
absoluteLayout.Children.Add(innerStackVoorAbsoluteLayout);
#endregion
#endregion
#endregion
Frame frame = new Frame();
frame.Content = absoluteLayout;
StackLayout.Children.Add(frame);
return StackLayout;
});
#endregion
FlowListView lstRelatieLijst = new FlowListView();
lstRelatieLijst.ItemsSource = lstRelatieItems;
lstRelatieLijst.FlowColumnTemplate = dataTemplate;
lstRelatieLijst.BackgroundColor = Color.LightGoldenrodYellow;
lstRelatieLijst.FlowColumnCount = 1;
lstRelatieLijst.HasUnevenRows = true;
#endregion
Can someone give me some advice how I can become something similar like the upper Xaml in code behind, please?
I already tried the following sources but unfortunately I doesn't work as expected. I hoped to see the same result or something similar like the XAML code. But after following their info,the FLowListView appears to be empty:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/templates/data-templates/creating
https://www.codeproject.com/Questions/516614/createplusdatatemplatepluscodeplusbehind
You should use
flowList.SetBinding(FlowListView.FlowItemsSourceProperty, "List"); instead of ItemsSource
Here is the working sample....
using DLToolkit.Forms.Controls;
using System;
using Xamarin.Forms;
namespace FlowListTest
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
LoadUI();
BindingContext = new BContext();
}
private void LoadUI()
{
var dataTemplate = new DataTemplate(() =>
{
var image = new Image();
image.SetBinding(Image.SourceProperty, "BgImage");
var titleLabel = new Label
{
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
TextColor = Color.White,
};
titleLabel.SetBinding(Label.TextProperty, "Title");
var subTitleLabel = new Label
{
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
TextColor = Color.White,
};
subTitleLabel.SetBinding(Label.TextProperty, "Subtitle");
return new StackLayout
{
BackgroundColor = Color.Pink,
Padding = 2,
HorizontalOptions = LayoutOptions.FillAndExpand,
Children = {
new Frame {
Content = new AbsoluteLayout {
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
Children = {
image,
new StackLayout {
Margin = new Thickness(20),
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Children = {
titleLabel,
subTitleLabel
}
}
}
}
}
}
};
});
var flowList = new FlowListView();
flowList.SetBinding(FlowListView.FlowItemsSourceProperty, "List");
flowList.FlowColumnTemplate = dataTemplate;
flowList.BackgroundColor = Color.LightGoldenrodYellow;
flowList.FlowColumnCount = 1;
flowList.HasUnevenRows = true;
var button = new Button { Text = "Add" };
button.Clicked += Button_Clicked
;
Content = new StackLayout
{
Children = {
button,
flowList
}
};
}
private void Button_Clicked(object sender, EventArgs e)
{
(BindingContext as BContext).Add();
}
}
public class Foo
{
public string BgImage { get; set; }
public string Title { get; set; }
public string Subtitle { get; set; }
}
public class BContext
{
public FlowObservableCollection<Foo> List { get; set; }
public BContext()
{
List = new FlowObservableCollection<Foo>
{
new Foo {
BgImage = "http://via.placeholder.com/350x150",
Title = "Title",
Subtitle = "SubTitle"
},
new Foo {
BgImage = "http://via.placeholder.com/350x150",
Title = "Title1",
Subtitle = "SubTitle1"
}
};
}
public void Add()
{
List.Add(new Foo
{
BgImage = "http://via.placeholder.com/350x150",
Title = "Title" + List.Count,
Subtitle = "SubTitle" + List.Count
});
}
}
}
I would like to know how to put a stacklayout into a grid case of xamarin forms and repeat tha pattern.
I decleare in my xaml my grid and the stacklayout.
<Grid x:Name="MyGrid" RowSpacing="0" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackLayout x:Name="MyLayout">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/>
</StackLayout.GestureRecognizers>
</StackLayout>
</Grid>
Then in my c# i wannt to create
var test = new List<Product>
{
new Product() {Desc = "DESC", Brand= "HelloWorld", Price= "30", Uri = "UriToPicture" },
new Product() {Desc = "DESC2", Brand= "HelloWorld2", Price= "30", Uri = "UriToPicture" }
};
Image PicProd = new Image { Aspect = Aspect.AspectFit };
PicProd.Source = FileImageSource.FromUri(new Uri(test[0].Uri));
Label Name= new Label { Text = test[0].Marque.ToString(), TextColor = Color.Black, HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center };
Label Desc = new Label { Text = test[0].Desc.ToString(), TextColor = Color.Black, HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center };
Label Price = new Label { Text = test[0].Prix.ToString(), TextColor = Color.Black, HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center };
MyLayout.Children.Add(PicProd);
MyLayout.Children.Add(Name);
MyLayout.Children.Add(Desc);
MyLayout.Children.Add(Price);
MyGrid.Children.Add(MyLayout, 0, 0);
MyGrid.Children.Add(MyLayout, 0, 1);
Content = MyGrid;
So I have two stacklayout elements that i want to display on two colomns(side by side) but i don't succed to display them correctly
You can set the Grid.Row and Grid.Column on elements to position them inside the grid. These are 0-based indexers. So in your case you could set the StackLayout as follows:
<StackLayout x:Name="MyLayout" Grid.Row="0" Grid.Column="0">
And in the next you could put:
<StackLayout x:Name="MyLayout" Grid.Row="0" Grid.Column="1">
UPDATE:
You cannot add the same instance of a control to a page twice, which is why only one of your items is showing up. You should instantiate 2 actual instances of your StackLayout. Remove the StackLayout from your XAML and declare it in code-behind. Then create 2 separate label instances and add those to the appropriate StackLayout. It should look something like this:
var test = new List<Product>
{
new Product() {Text1 = "DESC", Text2= "HelloWorld" },
new Product() {Text1 = "DESC2", Text2= "HelloWorld2" }
};
MyGrid.BackgroundColor = Color.Yellow;
var Name = new Label { Text = test[0].Text1.ToString(), TextColor = Color.Black, HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center };
var Desc = new Label { Text = test[0].Text2.ToString(), TextColor = Color.Black, HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center };
var MyLayout = new StackLayout();
MyLayout.BackgroundColor = Color.Red;
MyLayout.Children.Add(Name);
MyLayout.Children.Add(Desc);
MyGrid.Children.Add(MyLayout, 0, 0);
var Name2 = new Label { Text = test[0].Text1.ToString(), TextColor = Color.Black, HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center };
var Desc2 = new Label { Text = test[0].Text2.ToString(), TextColor = Color.Black, HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center };
var MyLayout2 = new StackLayout();
MyLayout2.BackgroundColor = Color.Blue;
MyLayout2.Children.Add(Name2);
MyLayout2.Children.Add(Desc2);
MyGrid.Children.Add(MyLayout2, 1, 0);
Another thing to keep in mind, the parameters for the Children.Add call want the column as the first parameter and then the row. Additionally you could use this extension method to simplify the process of adding children with spans etc.
public static class GridExtension
{
public static void AddChild(this Grid grid, View view, int row, int column, int rowspan = 1, int columnspan = 1)
{
if (row < 0) throw new ArgumentOutOfRangeException(nameof(row));
if (column < 0) throw new ArgumentOutOfRangeException(nameof(column));
if (rowspan <= 0) throw new ArgumentOutOfRangeException(nameof(rowspan));
if (columnspan <= 0) throw new ArgumentOutOfRangeException(nameof(columnspan));
if (view == null) throw new ArgumentNullException(nameof(view));
Grid.SetRow((BindableObject)view, row);
Grid.SetRowSpan((BindableObject)view, rowspan);
Grid.SetColumn((BindableObject)view, column);
Grid.SetColumnSpan((BindableObject)view, columnspan);
grid.Children.Add(view);
}
}
So I have two Stacklayout elements that i want to display on two colomns(side by side) but i don't succed to display them correctly
The problem is that you don't have two Stacklayout elements. Instead, you have one single instance that you pass two times to the grid using Add method.
If you want a second Stacklayout side by side, first create a new instance of a Stacklayout either in code or in XAML:
<StackLayout x:Name="MySecondLayout">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/>
</StackLayout.GestureRecognizers>
</StackLayout>
And pass it to your grid using Add method:
//... Populate "MySecondLayout" as you did for "MyLayout"
// Add your two layouts to the grid
MyGrid.Children.Add(MyLayout, 0, 0);
MyGrid.Children.Add(MySecondLayout, 0, 1);
If you want to use the exact same Stacklayout twice side by side, you must create two different instances of a Stacklayout.
I programmatically add a Border with a certain width and height to a grid. However, I want to get either one of the following:
Make the border keep aspect ratio and fill make it as big as possible inside the grid
Make the border scale whenever the grid scales down or up (so not particularily the biggest possible, more like a percentage of the grid)
At the moment this is the situation when I resize my window:
Color borderColor = (Color)ColorConverter.ConvertFromString(BorderColor);
Color backgroundColor = (Color)ColorConverter.ConvertFromString(BackgroundColor);
Border border = new Border();
border.BorderThickness = new Thickness(BorderSize);
border.CornerRadius = new CornerRadius(TopLeftCornerRadius, TopRightCornerRadius, BottomRightCornerRadius, BottomLeftCornerRadius);
border.BorderBrush = (SolidColorBrush)(new BrushConverter().ConvertFrom(BorderColor));
border.Background = (SolidColorBrush)(new BrushConverter().ConvertFrom(BackgroundColor));
border.Width = Width;
border.Height = Height;
border.Margin = new Thickness(10);
previewgrid.Children.Add(border);
The normal situation:
The scaled situation:
So I would like it to resize properly and stay inside the white rectangle. By the way, the white grid has a margin as you can see ;-)
Thanks in advance!
As lerthe61 suggested, just use a Viewbox with its Stretch property set to Uniform:
Color borderColor = (Color)ColorConverter.ConvertFromString(BorderColor);
Color backgroundColor = (Color)ColorConverter.ConvertFromString(BackgroundColor);
Border border = new Border();
border.BorderThickness = new Thickness(BorderSize);
border.CornerRadius = new CornerRadius(TopLeftCornerRadius, TopRightCornerRadius, BottomRightCornerRadius, BottomLeftCornerRadius);
border.BorderBrush = (SolidColorBrush)(new BrushConverter().ConvertFrom(BorderColor));
border.Background = (SolidColorBrush)(new BrushConverter().ConvertFrom(BackgroundColor));
border.Width = Width;
border.Height = Height;
border.Margin = new Thickness(10);
Viewbox viewBox = new Viewbox();
viewBox.Stretch = Stretch.Uniform;
viewBox.Child = border;
previewgrid.Children.Add(viewBox);
Please, note that this solution does not work if previewgrid is a Canvas.
I hope it can help you.
The simplest way:
<Grid Margin="50">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Border CornerRadius="50,0,0,50"
Background="Green" />
<Border CornerRadius="0"
Grid.Column="1"
Background="Green" />
<Border CornerRadius="0,50,50,0"
Grid.Column="2"
Background="Green" />
</Grid>
By C#:
myGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(50) });
myGrid.ColumnDefinitions.Add(new ColumnDefinition());
myGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(50) });
Border b1 = new Border
{
Background = new SolidColorBrush(Colors.Blue),
CornerRadius = new CornerRadius(100, 0, 0, 100)
};
Grid.SetColumn(b1, 0);
Border b2 = new Border
{
Background = new SolidColorBrush(Colors.Blue),
};
Grid.SetColumn(b2, 1);
Border b3 = new Border
{
Background = new SolidColorBrush(Colors.Blue),
CornerRadius = new CornerRadius(0, 100, 100, 0),
};
Grid.SetColumn(b3, 2);
myGrid.Children.Add(b1);
myGrid.Children.Add(b2);
myGrid.Children.Add(b3);
Normal:
Resized:
Is it good enough for you?
I'm developing WP8 app for my own needs and want it to have small live tile with text.
Since small tile cannot display text, I'm generating appropriate image with needed text.
Here is the code:
WriteableBitmap bmpSmall = new WriteableBitmap(159, 159);
var grid = new Grid();
grid.Width = bmpSmall.PixelWidth;
grid.Height = bmpSmall.PixelHeight;
var background = new Canvas();
background.Width = bmpSmall.PixelWidth;
background.Height = bmpSmall.PixelHeight;
SolidColorBrush backColor = new SolidColorBrush((Color)Application.Current.Resources["PhoneAccentColor"]);
background.Background = backColor;
var textBlock = new TextBlock();
textBlock.Text = "qwerty";
textBlock.FontWeight = FontWeights.Bold;
textBlock.HorizontalAlignment = HorizontalAlignment.Center;
textBlock.VerticalAlignment = VerticalAlignment.Center;
textBlock.FontSize = 28;
textBlock.Foreground = new SolidColorBrush(Colors.White);
grid.Children.Add(textBlock);
bmpSmall.Render(background, null);
bmpSmall.Render(grid, null);
bmpSmall.Invalidate();
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream imageStream = new IsolatedStorageFileStream("/Shared/ShellContent/smallTile.jpg", System.IO.FileMode.Create, isf))
{
bmpSmall.SaveJpeg(imageStream, 159, 159, 0, 100);
}
}
ShellTile tile = ShellTile.ActiveTiles.First();
FlipTileData tileData = new FlipTileData();
tileData.SmallBackgroundImage = new Uri(#"isostore:/Shared/ShellContent/smallTile.jpg", UriKind.Absolute);
tile.Update(tileData);
And result looks like:
As you see, text is aligned to top left corner. The question is "Why"? Since I'd set textBlock.HorizontalAlignment and textBlock.VerticalAlignment - I expect it in the center of the image.
For example the following XAML looks like you can expect and like I need:
<Grid Width="159" Height="159">
<Grid.Background>
<SolidColorBrush Color="{StaticResource PhoneAccentColor}"/>
</Grid.Background>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" FontSize="28" Foreground="White">qwerty</TextBlock>
</Grid>
What did I miss? How can I center text?
Give the following code a try:
WriteableBitmap bmpSmall = new WriteableBitmap(159, 159);
var grid = new Grid();
grid.Width = bmpSmall.PixelWidth;
grid.Height = bmpSmall.PixelHeight;
var background = new Canvas();
background.Width = bmpSmall.PixelWidth;
background.Height = bmpSmall.PixelHeight;
SolidColorBrush backColor = new SolidColorBrush((Color)Application.Current.Resources["PhoneAccentColor"]);
background.Background = backColor;
var textBlock = new TextBlock();
textBlock.Width = bmpSmall.PixelWidth;
textBlock.Text = "qwerty";
textBlock.FontWeight = FontWeights.Bold;
textBlock.HorizontalAlignment = HorizontalAlignment.Stretch;
textBlock.VerticalAlignment = VerticalAlignment.Center;
textBlock.FontSize = 28;
textBlock.Foreground = new SolidColorBrush(Colors.White);
textBlock.TextAlignment = TextAlignment.Center;
grid.Children.Add(background);
grid.Children.Add(textBlock);
grid.Measure(new Size(bmpSmall.PixelWidth, bmpSmall.PixelHeight));
grid.Arrange(new Rect(0,0,bmpSmall.PixelWidth, bmpSmall.PixelHeight));
grid.UpdateLayout();
bmpSmall.Render(grid, null);
bmpSmall.Invalidate();
I set the TextBlock width to the same as the rest of the tile, and set HorizontalAlignment to stretch, so that control would take up the whole width of the tile. Then I set the TextAlignment property to TextAlignment.Center, in order to center the text. Hope that helps!
Edit: Apparently for writable bitmaps, you must do the measure/arrange/layout steps yourself in order to render controls as you would think they should be rendered. Give this updated code a try, it should work this time!
You will have to set the HorizontalAlignment="Stretch" VerticalAlignment="Stretch" for grid also. Currently grid is only of size of its content i.e textblock.
After copying your code into an empty WPF application, I'm afraid to tell you that your code works just fine:
All I did was to set the Grid.Background to red and the TextBlock.Background to black to clarify the situation:
<Grid Width="159" Height="159">
<Grid.Background>
<SolidColorBrush Color="Red"/>
</Grid.Background>
<TextBlock Background="Black" HorizontalAlignment="Center"
VerticalAlignment="Center" FontWeight="Bold" FontSize="28"
Foreground="White">qwerty</TextBlock>
Therefore, I can only assume that you have a problem elsewhere in your code.
UPDATE >>>
Sorry, you're right, I did misunderstand you. However, after testing your C# code, the story is just the same:
This might look like the same image, but it actually comes from your C# code... I made a couple of little changes, but nothing that affected the position of the TextBlock:
Grid grid = new Grid();
grid.Background = Brushes.Red;
grid.Width = grid.Height = 159.0;
TextBlock textBlock = new TextBlock();
textBlock.Text = "qwerty";
textBlock.Background = Brushes.Black;
textBlock.FontWeight = FontWeights.Bold;
textBlock.HorizontalAlignment = HorizontalAlignment.Center;
textBlock.VerticalAlignment = VerticalAlignment.Center;
textBlock.FontSize = 28;
textBlock.Foreground = Brushes.White;
grid.Children.Add(textBlock);
this.Content = grid;
If you put this code into a new WPF project, you'll see that it works just fine, so that only leaves your WriteableBitmap object as the culprit of this problem... what are you using that for? If you're just adding it to your UI, then you can simply add the controls to the Window directly.