I'm adding a stackpanel to a mapcontrol. like below
But some of the points added before are on the top of my stackpanel. How to set my stackpanel topmost?
XAML:
<Grid x:Name="gridMain">
<maps:MapControl
x:Name="mapControl"
ZoomInteractionMode="GestureAndControl"
TiltInteractionMode="GestureAndControl"
RotateInteractionMode="GestureAndControl">
<!--ZoomLevel="{x:Bind ViewModel.ZoomLevel, Mode=OneWay}"
Center="{x:Bind ViewModel.Center, Mode=OneWay}"-->
<maps:MapItemsControl x:Name="MapItems">
<maps:MapItemsControl.ItemTemplate>
<DataTemplate>
<Grid Tapped="MagPoint_Tapped" maps:MapControl.NormalizedAnchorPoint="{Binding NormalizedAnchorPoint}" maps:MapControl.Location="{Binding Location}">
<Ellipse Canvas.ZIndex="0" Width="{Binding Mag5}" Height="{Binding Mag5}" Fill="{Binding MagColor}"/>
<!--<TextBlock Text="{Binding Mag}"/>-->
</Grid>
</DataTemplate>
</maps:MapItemsControl.ItemTemplate>
</maps:MapItemsControl>
</maps:MapControl>
</Grid>
And add panel code.
StackPanel sp = new StackPanel();
sp.Background = new SolidColorBrush(Colors.White);
sp.CornerRadius = new CornerRadius(15);
sp.BorderBrush = new SolidColorBrush(Colors.LightGray);
sp.BorderThickness = new Thickness(1);
sp.Width = 260;
sp.MinHeight = 180;
sp.Padding = new Thickness(10);
Canvas.SetZIndex(sp, 99999);
mapControl.Children.Add(sp);
Windows.UI.Xaml.Controls.Maps.MapControl.SetLocation(sp, new Geopoint(new BasicGeoposition { Longitude = (double)fi.geometry.coordinates[0], Latitude = (double)fi.geometry.coordinates[1] }));
Windows.UI.Xaml.Controls.Maps.MapControl.SetNormalizedAnchorPoint(sp, new Point(0.5, 1));
Your way of setting the ZIndex wouldn't work because the StackPanel and the items inside MapItemsControl are in different hosts.
With the help of Live Visual Tree, you can find out how exactly they get laid out.
In the screenshot above, the StackPanel's host (i.e. the first Canvas) is placed behind the MapOverlayPresenters host (i.e. the second Canvas where MapItemsControl is inserted). So in order to have the StackPanel sit above them, you will need to manually set the ZIndex of the first Canvas to 1.
Once you understand this, the solution becomes simple -
Loaded += (s, e) =>
{
// GetChildByName comes from
// https://github.com/JustinXinLiu/Continuity/blob/0cc3d7556c747a060d40bae089b80eb845da84fa/Continuity/Extensions/UtilExtensions.cs#L44
var layerGrid = mapControl.GetChildByName<Grid>("LayerGrid");
var canvas1 = layerGrid.Children.First();
Canvas.SetZIndex(canvas1, 1);
};
Hope this helps!
Related
I am working on MapControl in Windows 10 and I want to display Location Address above map icon. I know how to add a map icon but not aware of adding a UI element above it. I added Map Icon using following code
MapControl map = frameworkElement as MapControl;
map.MapServiceToken= "my service token";
BasicGeoposition councilPosition = new BasicGeoposition()
{
Latitude = Convert.ToDouble(Info.GetType().GetRuntimeProperty("LATITUDE").GetValue(Info, null)),
Longitude = Convert.ToDouble(Info.GetType().GetRuntimeProperty("LONGITUDE").GetValue(Info, null))
};
Geopoint pinPoint = new Geopoint(councilPosition);
MapIcon locationPin = new MapIcon();
locationPin.Image= RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Images/pushpin.png"));
locationPin.Title = councilInfo.COUNCIL_NAME;
locationPin.CollisionBehaviorDesired = MapElementCollisionBehavior.RemainVisible;
locationPin.Location = councilPoint;
locationPin.NormalizedAnchorPoint = new Point(0.5, 1.0);
locationPin.ZIndex = 0;
map.MapElements.Add(locationPin);
await map.TrySetViewAsync(locationPin.Location, 15D, 0, 0, MapAnimationKind.Bow);
and I want to achieve same as below screenshots
Since programmatic adding MapIcons is hectic for custom template. Here's how I am using map Control inside my app
<maps:MapControl x:Name="MapControl" MapServiceToken="YourToken" >
<maps:MapItemsControl ItemsSource="{Binding YourData, Mode=TwoWay}">
<maps:MapItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Tapped="MapIcon_Tapped" Orientation="Horizontal">
<Image Height="30" VerticalAlignment="Top" maps:MapControl.Location="{Binding Location}" maps:MapControl.NormalizedAnchorPoint="0.5,0.5" Source="ms-appx:///Images/pushpin.png"/>
<Border BorderThickness="1" BorderBrush="LightGray" Visibility="{Binding DetailsVisibility}">
<StackPanel x:Name="MapIcon" Background="White" >
<TextBlock Text="{Binding yourMin}" Foreground="Black" FontWeight="SemiBold" FontSize="16" Margin="5" TextWrapping="WrapWholeWords" />
<TextBlock Text="{Binding YourCar}" Foreground="Gray" FontWeight="SemiBold" FontSize="12" Margin="5" TextWrapping="WrapWholeWords"/>
<Image Source="Your Arrow"/>
</StackPanel>
</Border>
</StackPanel>
</DataTemplate>
</maps:MapItemsControl.ItemTemplate>
</maps:MapItemsControl>
</maps:MapControl>
Now here you just need to keep adding data to YourData to add more pushpin.
There are two properties added
1. Location- Is of Geopoint type which will take care of position where pushpin should be placed based on latitude and longitude e.g temp.Location = new Geopoint(new BasicGeoposition { Latitude = double.Parse(temp.Lat), Longitude = double.Parse(temp.Long) });
2. Visibility- This will be used to handle the pushpin detail visibility to be available only on taping it. eg. temp.DetailsVisibility = Windows.UI.Xaml.Visibility.Collapsed;
You will need to add these values to YourData for binding.
I know how to add a map icon but not aware of adding a UI element above it.
If you need to add UIElement above the MapIcon, a possible way is to add UIElement into MapControl’s Children and set to the same coordinate( MapControl.SetLocation).
Here is a simple sample:
BasicGeoposition snPosition = new BasicGeoposition() { Latitude = 47.643, Longitude = -122.131 };
Geopoint snPoint = new Geopoint(snPosition);
Grid MyGrid = new Grid();
MyGrid.Background = new SolidColorBrush(Windows.UI.Colors.Blue);
TextBlock text = new TextBlock();
text.Text = "Hello";
text.Width = 200;
MyGrid.Children.Add(text);
MyMapControl.Center = snPoint;
MyMapControl.ZoomLevel = 14;
// Get the address from a `Geopoint` location.
MapLocationFinderResult result = await MapLocationFinder.FindLocationsAtAsync(snPoint);
if (result.Status == MapLocationFinderStatus.Success)
{
text.Text = "Street = " + result.Locations[0].Address.Street;
}
MyMapControl.Children.Add(MyGrid);
MapControl.SetLocation(MyGrid, snPoint);
MapControl.SetNormalizedAnchorPoint(MyGrid, new Point(0.5, 0.5));
Screenshot(gif):
I am working on Windows 8 application in C#/XAML.
I have a list of steps to show and the list can have one to many steps.
I have tried the GridView and ListView controls, but with those, it is not possible to have each element have its own height (because one step might have only one line of text, and the next one 3 lines, for example). The VariableSizedGridview does not help either.
What I am trying to achieve is something like the way cooking steps are shown in the Microsoft Bing Food & Drink app. So, steps are shown in rows in the first column, and when the end of the page is reached, it creates a second column, and so on. Like so :
Could anyone please help me find a way to achieve this?
What control to use and how?
It looks very simple, but I was not able to find any solution while searching online.
Thank you
Here is what I have done with the Gridview control (the Listview was quite similar) :
<Grid Name="gridSteps" Grid.Column="3" Margin="25,69,25,69">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="ÉTAPES" FontSize="22" FontWeight="Bold"></TextBlock>
<GridView Grid.Row="1" Name="gvGroupSteps" SelectionMode="None" IsHitTestVisible="False" VerticalAlignment="Top">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Width="400">
<TextBlock Text="{Binding Order}" Margin="0,15,0,0" FontSize="20" Foreground="Bisque"></TextBlock>
<TextBlock Text="{Binding Description}" Margin="0,5,0,0" FontSize="18" TextWrapping="Wrap"></TextBlock>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel Background="#FFC9C9C9">
<TextBlock Text="{Binding GroupName}" FontSize="20" FontWeight="SemiBold"></TextBlock>
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
</Grid>
You may want to post the XAML that you have tried. It sounds like to me that you need to nest your view items. Consider this very simple example:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<ListView>
<ListViewItem>Step 1</ListViewItem>
<ListViewItem>
<ListView>
<ListViewItem>Step 1a</ListViewItem>
<ListViewItem>Step 1b</ListViewItem>
<ListViewItem>Step 1c</ListViewItem>
</ListView>
</ListViewItem>
<ListViewItem>Step 2</ListViewItem>
</ListView>
</Grid>
I have tried the GridView and ListView controls, but with those, it is not possible to have each element have its own height
My recollection is that you can in fact have elements with different heights using those controls. These are both types of ItemsControl, which supports data templating, which in turn allows you to customize the appearance of each item, including its height.
That said, you may find that the simpler ListBox suits your needs in this case. It's hard to say without a code example or other details.
You should read MSDN's Data Templating Overview, which has a thorough discussion of the whole process, along with some good examples of what you can do. Pay particular attention to the section named "Choosing a DataTemplate Based on Properties of the Data Object". While a single template could still have variable height, clearly by using a different template according to your specific needs you can customize each item's style to your heart's content.
If this does not address your question, please provide a more detailed question. You should include a good, minimal, complete code example that shows clearly what you've tried, explaining precisely what that code does and how that's different from what you want it to do.
I have been looking all over the internet for a solution, but could not manage to find anything.
So i decided to do everything myself in C# code.
In short, in have a StackPanel with Orientation set to Horizontal, and I add a Grid to it and add rows to that Grid for every item i have. When the maximum height is reached (based on the screen Height), I add a new Grid to the StackPanel, and so on.
Here is my code if anyone needs it :
// Nombre de lignes maximal (16 lignes à 1080p)
int maxCharCount = (int)Window.Current.Bounds.Height * 16 / 1080;
spIngredients.Children.Clear();
foreach (var groupIngredient in db.Table<GroupIngredient>().Where(x => x.RecipeId == _currentRecipe.Id))
{
int linesCount = 0;
int row = 0;
var gGroup = new Grid();
spIngredients.Children.Add(gGroup);
gGroup.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
var groupName = new TextBlock() { Text = groupIngredient.Name, FontSize = 20, FontWeight = FontWeights.SemiBold, Margin = new Thickness(10) };
gGroup.Children.Add(groupName);
Grid.SetRow(groupName, row);
foreach (var ingredient in db.Table<Ingredient>().Where(x => x.GroupIngredientId == groupIngredient.Id))
{
// Nombre de lignes, split à 45 char
linesCount += 1 + ingredient.IngredientFull.Length / 45;
if (linesCount >= maxCharCount)
{
var gCol = new Grid();
spIngredients.Children.Add(gCol);
gCol.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
var col = new TextBlock() { Text = "", FontSize = 20, FontWeight = FontWeights.SemiBold, Margin = new Thickness(10) };
gCol.Children.Add(col);
gGroup = gCol;
row = 0;
linesCount = 0;
Grid.SetRow(col, row);
}
row++;
ingredient.Quantity = ingredient.Quantity * multiplier;
gGroup.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
var ingredientName = new TextBlock() { Text = ingredient.IngredientFull, Margin = new Thickness(10), FontSize = 18, TextWrapping = TextWrapping.Wrap, MaxWidth = 300 };
gGroup.Children.Add(ingredientName);
Grid.SetRow(ingredientName, row);
}
}
I have a problem with the performance of the wpf gui.
At first I will explain what I have done.
I read from a Database different chat data, mostly text but sometimes there is an icon in the middle of the text, like a smiley or similar. Or, there are no text just a Image.
I have this all done by using a Flowdocument and use a Textblock with inlines. Oh I forgot, I use wpf, sorry.
Thats work great, BUT at the moment the Flowdocument will be painted to the RichTextbox or FlowdocumentReader, its take a long time and the gui freeze. I have think about Virtualizing but a RichTextBox doesn't use this. So my next idea was to use a Listbox and set as item a Richtextbox for every Chatbubble. A Chat can contain round about 20.000 Chatbubbles.
So now I want to use Databinding but I doesn't find a way to bind the inlines of a Textblock.
So now some code.
<DataTemplate x:Key="MessageDataTemplate" DataType="{x:Type classes:Message}">
<Grid>
<RichTextBox x:Name="rtbChat"
SpellCheck.IsEnabled="False"
VerticalScrollBarVisibility="Auto"
VerticalContentAlignment="Stretch">
<FlowDocument
FontFamily="Century Gothic"
FontSize="12"
FontStretch="UltraExpanded">
<Paragraph>
<Figure>
<BlockUIContainer>
<Border>
<Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="80"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="15"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock x:Name="tUser"
Foreground="Gray"
TextAlignment="Right"
FontSize="10"
Grid.Row="0"
Grid.Column="1"
Text="{Binding displayUserName}"/>
<TextBlock x:Name="tTime"
Foreground="Gray"
TextAlignment="Left"
FontSize="10"
Grid.Row="0"
Grid.Column="0"
Text="{Binding sendTime}"/>
<TextBlock x:Name="tMessage"
Foreground="Black"
TextAlignment="Justify"
FontSize="12"
Height="NaN"
TextWrapping="Wrap"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
Text="{Binding contentText}" />
<Image x:Name="tImage"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
Height="NaN"
Source="{Binding imageSend}"/>
</Grid>
</Border>
</Border>
</BlockUIContainer>
</Figure>
</Paragraph>
</FlowDocument>
</RichTextBox>
</Grid>
</DataTemplate>
So this is not final, I'm porting this from Source-code to xaml and some setters are missing at this moment.
I have benchmark the timings and everything works fine, 10 ms for the sqlite, round about 4 sec for the building of the FlowDocument but up to 5 min to paint the FlowDocument in the RichTextBox. I know that is why the hole box is painted, also the part that is not visible.
I hope that is understandable, if not ask me :)
Here the Source-Code before ported to xaml.
var rtBox = new RichTextBox
{
//IsEnabled = false,
BorderThickness = new Thickness(0, 0, 0, 0)
};
var doc = new FlowDocument();
Contact contact = null;
contact = _mess.remote_resource != "" ? _contacts.Find(x => x._jid == _mess.remote_resource) : _contacts.Find(x => x._jid == _mess.key_remote_jid);
var para = new Paragraph();
//--- Style of the message -----
para.Padding = new Thickness(0);
BlockUIContainer blockUI = new BlockUIContainer();
blockUI.Margin = new Thickness(0, 0, 0, 0);
blockUI.Padding = new Thickness(0);
blockUI.TextAlignment = _mess.key_from_me == 1 ? TextAlignment.Right : TextAlignment.Left;
Border bShadow = new Border();
bShadow.Width = 231;
bShadow.BorderBrush = Brushes.LightGray;
bShadow.BorderThickness = new Thickness(0, 0, 0, 1);
Border b2 = new Border();
b2.Width = 230;
b2.BorderBrush = Brushes.Gray;
b2.Background = Brushes.White;
b2.BorderThickness = new Thickness(0.5);
b2.Padding = new Thickness(2);
Grid g = new Grid();
g.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(150,GridUnitType.Star) });
g.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(80) });
g.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(15) });
g.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(25,GridUnitType.Auto) });
TextBlock tUser = new TextBlock()
{
Foreground = Brushes.Gray,
TextAlignment = TextAlignment.Right,
FontSize = 10,
};
tUser.SetValue(Grid.RowProperty, 0);
tUser.SetValue(Grid.ColumnProperty, 1);
if(contact != null)
tUser.Text = _mess.key_from_me == 1 ? "ich" : (contact._displayName == "" ? Whatsapp.Contacs.convertJidToNumber(_mess.remote_resource) : contact._displayName);
else
{
tUser.Text = Whatsapp.Contacs.convertJidToNumber(_mess.remote_resource);
}
TextBlock tTime = new TextBlock()
{
Foreground = Brushes.Gray,
TextAlignment = TextAlignment.Left,
FontSize = 10,
};
tTime.SetValue(Grid.RowProperty, 0);
tTime.SetValue(Grid.ColumnProperty, 0);
tTime.Text = UnixTime.TimeReturnUnix2DateUtc(_mess.timestamp, timeZone).ToString();
TextBlock tMessage = new TextBlock()
{
Foreground = Brushes.Black,
TextAlignment = TextAlignment.Justify,
FontSize = 12,
Height = Double.NaN,
TextWrapping = TextWrapping.Wrap
};
tMessage.SetValue(Grid.RowProperty, 1);
tMessage.SetValue(Grid.ColumnProperty, 0);
tMessage.SetValue(Grid.ColumnSpanProperty, 2);
for (var i = 0; i < _mess.data.Length; i += Char.IsSurrogatePair(_mess.data, i) ? 2 : 1)
{
var x = Char.ConvertToUtf32(_mess.data, i);
if (EmojiConverter.EmojiDictionary.ContainsKey(x))
{
//Generate new Image from Emoji
var emoticonImage = new Image
{
Width = 20,
Height = 20,
Margin = new Thickness(0, -5, 0, -5),
Source = EmojiConverter.EmojiDictionary[x]
};
//add grafik to FlowDocument
tMessage.Inlines.Add(emoticonImage);
}
else
{
tMessage.Inlines.Add(new Run("" + _mess.data[i]));
}
}
g.Children.Add(tUser);
g.Children.Add(tTime);
g.Children.Add(tMessage);
b2.Child = g;
bShadow.Child = b2;
blockUI.Child = bShadow;
Figure fig = new Figure(blockUI);
fig.Padding = new Thickness(0);
fig.Margin = new Thickness(0);
fig.Height = new FigureLength(0, FigureUnitType.Auto);
para.Inlines.Add(fig);
doc.Blocks.Add(para);
rtBox.Document = doc;
msgList.Add(rtBox);
Greetings and thanks for your help.
One method would be to virtualize using a ListBox, certainly. Arguably better methods would be to dynamically load in the required messages or make your own virtualized control (issues with the default ListBox virtualization include that you have to scroll entire items in a single go to get virtualization working... which can suck a bit from a UX perspective in some cases.)
From the sound of it still taking forever to load, the virtualization you've set up isn't working right...
The main thing that you require to get virtualization working is that you need to have the ScrollViewer inside the ListBox template have CanContentScroll=True. Ie do:
<ListBox ScrollViewer.CanContentScroll="True" .... >
Or give the ListBox a template similar to below:
<ControlTemplate>
<Border BorderBrush="{TemplateBinding Border.BorderBrush}"
BorderThickness="{TemplateBinding Border.BorderThickness}"
Background="{TemplateBinding Panel.Background}"
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}">
<ScrollViewer Focusable="False"
Padding="{TemplateBinding Control.Padding}"
MaxHeight="{TemplateBinding Control.MaxHeight}"
CanContentScroll="True">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
Also, unless you want to actually select previous messages, maybe a ListBox isn't what you want, and you actually want an ItemsControl? See Virtualizing an ItemsControl? for more on that.
Addition 1 - Smooth Scrolling + Virtualization:
See below - if you also want smooth scrolling, might be worth looking at a TreeView - see http://classpattern.com/smooth-scrolling-with-virtualization-wpf-list.html#.VBHWtfldXSg - though I can't vouch for if this actually works at the moment, just discovered it myself!
Addition 2 - Clarification RE needed elements
As in my comments below, if you're not editing everything, you can get rid of all the tags:
<Grid><RichTextBox><FlowDocument><Paragraph><Figure>
In the data template. You probably can't bind the Text of the message to the contentText in the DataTemplate, and will have to have a bit of behind-the-scenes code to dynamically generate the inlines for the TextBlock.
Addition 3 - How to bind a TextBlock to contain images etc from XAML
Okay, so overall (neglecting some styling), I suggest the following:
<DataTemplate x:Key="MessageDataTemplate" DataType="{x:Type classes:Message}">
<Border>
<Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="80"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="15"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock x:Name="tUser"
Foreground="Gray"
TextAlignment="Right"
FontSize="10"
Grid.Row="0"
Grid.Column="1"
Text="{Binding displayUserName}" />
<TextBlock x:Name="tTime"
Foreground="Gray"
TextAlignment="Left"
FontSize="10"
Grid.Row="0"
Grid.Column="0"
Text="{Binding sendTime}" />
<TextBlock x:Name="tMessage"
Foreground="Black"
TextAlignment="Justify"
FontSize="12"
Height="NaN"
TextWrapping="Wrap"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
classes:TextBlockInlineBinder.Inlines="{Binding contentInlines}" />
<Image x:Name="tImage"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
Height="NaN"
Source="{Binding imageSend}" />
</Grid>
</Border>
</Border>
</DataTemplate>
Note the line classes:TextBlockInlineBinder.Inlines="{Binding contentInlines}" on the message TextBlock. This is in order to be able to bind to Inlines... Basically, this not a dependency property, so cannot be directly bound to!
Instead, we can use the custom static class TextBlockInlineBinder below to create a static dependency property to add to our TextBlock, which when it is updated, it runs the InlinesChanged method to update the Inlines:
public static class TextBlockInlineBinder
{
#region Static DependencyProperty Implementation
public static readonly DependencyProperty InlinesProperty =
DependencyProperty.RegisterAttached("Inlines",
typeof(IEnumerable<Inline>),
typeof(TextBlockInlineBinder),
new UIPropertyMetadata(new Inline[0], InlinesChanged));
public static string GetInlines(DependencyObject obj)
{
return (string)obj.GetValue(InlinesProperty);
}
public static void SetInlines(DependencyObject obj, string value)
{
obj.SetValue(InlinesProperty, value);
}
#endregion
private static void InlinesChanged(DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
var value = e.NewValue as IEnumerable<Inline>;
var textBlock = sender as TextBlock;
textBlock.Inlines.Clear();
textBlock.Inlines.AddRange(value);
}
}
Finally, the binding (which I've bound to a contentInlines property on your Message class) will need to be of type IEnumerable<Inline>, ie something like:
public IEnumerable<Inline> contentInlines
{
get {
var inlines = new List<Inline>();
for (var i = 0; i < _mess.data.Length; i += Char.IsSurrogatePair(_mess.data, i) ? 2 : 1)
{
var x = Char.ConvertToUtf32(_mess.data, i);
if (EmojiConverter.EmojiDictionary.ContainsKey(x))
{
//Generate new Image from Emoji
var emoticonImage = new Image
{
Width = 20,
Height = 20,
Margin = new Thickness(0, -5, 0, -5),
Source = EmojiConverter.EmojiDictionary[x]
};
inlines.Add(emoticonImage);
}
else
{
inlines.Add(new Run("" + _mess.data[i]));
}
}
return inlines;
}
}
I've got a StackPanel which I need to fill in with ExpanderViews based on my data.
I am creating the ExpanderViews in code-behind and assigning to it, the DataTemplate present in the XAML.
The problem is, I am able to create the ExpanderView programmatically, but the DataTemplate approach doesn't work. All I can see is the "Expander Header" which doesn't show the items after click.
However, I can add Items manually to the ExpanderView and it shows the Items.
Please help!
C# Code:
ExpanderView expandOne = new ExpanderView()
{
Width = 400,
Margin = new Thickness(2),
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Expander = new Border()
{
Width = 400,
Background = new SolidColorBrush(Colors.Brown),
Child = new TextBlock()
{
Text = "Expander Header",
FontSize = 34,
Foreground = new SolidColorBrush(Colors.Black),
Margin = new Thickness(40, 5, 5, 5),
},
},
};
// Assign DataTemplate
DataTemplate temp = (DataTemplate)FindName("ItemTemplateName");
expandOne.ItemTemplate = temp;
// add ExpanderView to StackPanel
this.MyStackPanel.Children.Add(expandOne);
XAML Code:
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="ItemTemplateKey" x:Name="ItemTemplateName">
<ListBox Grid.Row="0" x:Name="ItemListBox">
<ListBox.Items>
<TextBlock Text="Filter Content 1" Foreground="Black"/>
<TextBlock Text="Filter Content 2" Foreground="Black"/>
<TextBlock Text="Filter Content 3" Foreground="Black"/>
</ListBox.Items>
</ListBox>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
If anyone still looking for an answer, I solved this by using the solution mentioned in
DataBinding to WP8 Toolkit ExpanderView
How to add a StackPanel in a Button using c# code behind (i.e. convert the following XAML to C# )? There is no Button.Children.Add...
<Button>
<StackPanel Orientation="Horizontal" Margin="10">
<Image Source="foo.png"/>
</StackPanel>
</Button>
Image img = new Image();
img.Source = new BitmapImage(new Uri("foo.png"));
StackPanel stackPnl = new StackPanel();
stackPnl.Orientation = Orientation.Horizontal;
stackPnl.Margin = new Thickness(10);
stackPnl.Children.Add(img);
Button btn = new Button();
btn.Content = stackPnl;
Set Button.Content instead of using Button.Children.Add
As a longer explanation:
Button is a control which "only has 1 child" - its Content.
Only very few controls (generally "Panels") can contain a list of zero or more Children - e.g. StackPanel, Grid, WrapPanel, Canvas, etc.
As your code already shows, you can set the Content of a Button to be a Panel - this would ehn allow you to then add multiple child controls. However, really in your example, then there is no need to have the StackPanel as well as the Image. It seems like your StackPanel is only adding Padding - and you could add the Padding to the Image rather than to the StackPanel if you wanted to.
Use like this
<Window.Resources>
<ImageSource x:Key="LeftMenuBackgroundImage">index.jpg</ImageSource>
<ImageBrush x:Key="LeftMenuBackgroundImageBrush"
ImageSource="{DynamicResource LeftMenuBackgroundImage}"/>
</Window.Resources>
and in Codebehind
Button btn = new Button();
btn.HorizontalContentAlignment = HorizontalAlignment.Stretch;
btn.VerticalContentAlignment = VerticalAlignment.Stretch;
StackPanel stk = new StackPanel();
stk.Orientation = Orientation.Horizontal;
stk.Margin = new Thickness(10, 10, 10, 10);
stk.SetResourceReference(StackPanel.BackgroundProperty, "LeftMenuBackgroundImageBrush");
btn.Content = stk;
In Xaml :
<Button x:Name="Btn" Click="Btn_Click" Orientation="Horizontal" Margin="10">
<StackPanel>
<Image Source="foo.png" Height="16" Width="16"/>
</StackPanel>
</Button>
In C# :
Button btn = new Button();
StackPanel panel = new StackPanel();
Image img = new Image
{
Source = "../foo.png"
}
panel.Children.Add(img);
btn.Content = panel;
I advise you to put the image in xaml resources :
<Window.Resources>
<BitmapImage x:Key="Img" UriSource="/Img/foo.png"/>
</Window.Resources>
And call it like this :
Image img = new Image
{
Source = (BitmapImage)FindResource("Img")
};