How to bind absolute coordinates of a shape/control inside Canvas - xaml

On a Windows 8.1 Metro app, I'm trying bind a collection of shapes from my view model into MainPage.xaml. Each shape will have a Left, Top and also a PathData which will be a RectangleGeometry that contains the rectangle that I want drawn inside the canvas at the corresponding position.
This is the XAML :
<Grid Background="Black">
<ItemsControl ItemsSource="{Binding Shapes}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Top" Value="{Binding Top}"/>
<Setter Property="Canvas.Left" Value="{Binding Left}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Path Data="{Binding PathData}" Stroke="White" StrokeThickness="3" Canvas.Left="{Binding Left}" Canvas.Top="{Binding Top}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
The data context is set and working correctly. I populate the Shapes from MainViewModel and the rectangles do appear on the screen, but the problem is I can't get the rectangles to be placed at the exact Left and Top locations inside the Canvas, i.e. they are just placed at (0,0).
I tried both binding the Path's Canvas.Left and Canvas.Top (the obvious method I tried) as well as setting an ItemContainerStyle with a Style (a method I found from a WPF example) that is supposed to do the same. But neither of these work (I've added both methods in the xaml for reference).
So what am I doing wrong and how do I make the rectangles appear at the corresponding positions ?
Edit : My question is the same as this one for WPF except that I'm targeting windows metro/uwp for which that accepted answer doesn't work.

Got around the problem by binding into a Transform instead.
<Path Data="{Binding PathData}" Stroke="White" StrokeThickness="3">
<Path.RenderTransform>
<CompositeTransform TranslateX="{Binding Left}" TranslateY="{Binding Top}"/>
</Path.RenderTransform>
</Path>

Related

uwp adaptive gridview renders 1st element wrong

I am using AdaptiveGridView from UWP Community toolkit.
The Very first Item displays horribly wrong and all other Items are displayed just fine.
See in the picture below the 1st item has bigger Folder Image than others.
XAML
<Style TargetType="controls:AdaptiveGridView" x:Key="MainAdaptiveStyle">
<Setter Property="SelectionMode" Value="None"/>
<Setter Property="StretchContentForSingleRow" Value="False"/>
<Setter Property="DesiredWidth" Value="220"/>
<Setter Property="IsItemClickEnabled" Value="True"/>
<Setter Property="animations:ReorderGridAnimation.Duration" Value="400"/>
</Style>
<PivotItem Header="Folders">
<controls:AdaptiveGridView Name="FoldersLibraryGridView"
Style="{StaticResource MainAdaptiveStyle}"
ItemsSource="{x:Bind ViewModel.Folders}">
<controls:AdaptiveGridView.ItemTemplate>
<DataTemplate x:DataType="data:FolderItem">
<userTemplates:FolderTemplate />
</DataTemplate>
</controls:AdaptiveGridView.ItemTemplate>
</controls:AdaptiveGridView>
</PivotItem>
<....below is user control which is used the DataTemplate, known as FolderTemplate...>
<Grid >
<Grid.Resources>
<Style TargetType="Image" x:Key="ThumbImageStyle" >
<Setter Property="Stretch" Value="UniformToFill"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="8"/>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="8*"/>
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<Border x:Name="ThumbImage" Grid.Row="0">
<Border.Background>
<SolidColorBrush Color="{ThemeResource SystemAccentColor}" Opacity="0.5"/>
</Border.Background>
<Image Source="ms-appx:///Assets/FolderIcon.png"
Style="{StaticResource ThumbImageStyle}"
/>
</Border>
<Border Background="{ThemeResource SystemAltHighColor}" Grid.Row="1" Padding="8,0,4,0">
<TextBlock Text="{x:Bind FolderItem.MyFolder.DisplayName}"
Style="{StaticResource GridViewVideoName}"/>
</Border>
</Grid>
UPDATE
as You can see in the picture below, market with red line, right side of each item is faded where the folder name textblock ends, and this occurs only when ItemHeight is Explicitly set on the ApativeGridView
I think the fix is simple. First have a look at the description of this control on GitHub -
/// <remarks>
/// The number and the width of items are calculated based on the
/// screen resolution in order to fully leverage the available screen space. The property ItemsHeight define
/// the items fixed height and the property DesiredWidth sets the minimum width for the elements to add a
/// new column.</remarks>
I believe ItemsHeight is a typo there. It really should be ItemHeight. You just need to specify it (e.g. <controls:AdaptiveGridView ItemHeight="280" ... /> and the problem should go away.
Update
Your second issue is related to the DropShadowPanel in the toolkit. If you resize the window a bit you will notice that the shadows then render properly.
I had a look at the default style of the control and the HorizontalContentAlignment property is set to Left initially. So it looks like the control doesn't properly resize its inner shadow component when the size is changed.
But since you have already got a local style, you can just set it to Stretch and the issue should go away.
<Style TargetType="controls:DropShadowPanel"
x:Key="MainDropShadow">
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
Update 2
OK, so here is the reason why initially the shadow is not stretching -
The shadow size is calculated based on the Content of the DropShadowPanel control, but the shadow only monitors the SizeChanged event of the control to update its size.
What's happening in your case is that your Grid (direct child of the DropShadowPanel control) was initially arranged with a smaller size, then the shadow size was set, and then when the size of your Grid updates, because the size of DropShadowPanel is still with the same size, no SizeChanged will be invoked, hence the shadow size is not re-calculated. If you have the toolkit source code, you should be able to simply switch to monitor the SizeChanged of the Content instead and the problem should go away.
When you are setting HorizontalContentAlignment to Stretch, you are effectively saying "the child should have the same size of the parent". So when the shadow is initially sized, your Grid is already at the same size of its parent. But I feel like they must have been using Left for a reason and this should just be a temporary fix for your case.

UWP Community Toolkit AdaptiveGridView control with one item only

I am making a media app with using UWP Community toolkit nuget package to use AdaptiveGridView Control, in order to show the video library contents.
Problem: When the items are very few or for example I have only 1 item it expands over the whole available width, which looks very bad, considering the fact its height is limited and doesn't changes and only width expands on whole screen, so the thumbnail of my item looks very bad. So when I have 4 or lesser items in a row (in this specific laptop resolution) they look bad due to width expansion, but more than 5 items in a row look good because they proportionate very good.
Attempt:
I tried to set max width property of stackpanel in data template of my item so that the item doesn't expand more than a specific width and it works good, but now the problem is the distance between the items, my content of item (stackpanel) remains limited but whole gridviewitem expands hence covering a lot of useless space, as show in the image below.
blue question marks show the useless space due to expansion of each item
red line box show the actual boundary of one item with expanded extra space.
Obviously the space decreases if I resize the window to smaller screen, but this is not optimal for all screen sizes.
Summary:
The default setting of adaptiveGridView (as in UWP community toolkit samples) works perfect if I have a lot of items, i.e: more than 5. But if item is one or 2 it expands all over the screen which looks bad because width becomes almost 700 at full expansion and height remains at 156 as I set it to be 156, if I remove the height of image one item will take whole screen, if there is 1 item only and that is not what I want because that will also look bad to the user (obviously).
here is my code.
gridview
<controls:AdaptiveGridView Name="SuggestionGridView"
Style="{StaticResource MainGridView}"
SelectionChanged="SelectionChanged"
ItemsSource="{x:Bind Suggestions, Mode=OneWay}">
<controls:AdaptiveGridView.ItemTemplate>
<DataTemplate x:DataType="data:Video">
<StackPanel Margin="4" MaxWidth="276">
<Grid>
<Image Source="{x:Bind Thumbnail}" Style="{StaticResource GridViewImage}"/>
<Border Style="{StaticResource TimeBorder}">
<TextBlock Text="{x:Bind Duration}" Foreground="White"/>
</Border>
</Grid>
<TextBlock Text="{x:Bind Name}" Style="{StaticResource GridViewVideoName}"/>
<TextBlock Text="{x:Bind ParentName}" Style="{StaticResource GridViewParentName}"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
<TextBlock Text="{x:Bind Views}" Style="{StaticResource GridViewViews}"/>
<TextBlock Text="Views" HorizontalAlignment="Right"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</controls:AdaptiveGridView.ItemTemplate>
</controls:AdaptiveGridView>
Styles
<Style TargetType="controls:AdaptiveGridView" x:Key="MainGridView">
<Setter Property="Grid.Row" Value="1"/>
<Setter Property="OneRowModeEnabled" Value="False"/>
<Setter Property="DesiredWidth" Value="264"/>
<Setter Property="SelectionMode" Value="Single"/>
</Style>
<Style TargetType="Image" x:Key="GridViewImage">
<Setter Property="Height" Value="156"/> <!--if I remove this property then one item expands to full availble height and width and looks really bad specially with the thumbnail.-->
<Setter Property="Stretch" Value="UniformToFill"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
There's already a property that helps you in this case. Try setting StretchContentForSingleRow to False on the control.

How to take whole width of the screen when binding dynamic values in Universal windows Application

I try to populate radio buttons dynamically in Universal windows application. I already wrote VisualState for different
of screens. Now I try to populate the radio button, which are they have to take the whole width of the window. I able to set fixed width for every VisualState But I think that may not good practice and difficult to handle further.
<GridView Grid.Row="1" Height="auto" Width="auto" HorizontalAlignment="Stretch" ItemsSource="{Binding DamageLocationList}">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Horizontal" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemTemplate>
<DataTemplate x:DataType="model:DamageLocations">
<Grid>
<RadioButton Style="{StaticResource ButtonRadioButtonStyle}" HorizontalContentAlignment="Center" HorizontalAlignment="Stretch" IsChecked="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}" Content="{Binding DamageLocation}" Margin="0" Click="RadioButton_Checked" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
As #Ashok Rathod said, you can try using UniformGrid as the ItemsPanel of your Grid to make your radio buttons take the whole width of your app's window.
Although UniformGrid is not exist in UWP. But we can implement it by ourselves or use a third party UniformGrid like what in WinRTXamlToolkit.
Using WinRTXamlToolkit for example, we can using
<toolkit:UniformGrid Rows="1" />
instead of
<VariableSizedWrapGrid Orientation="Horizontal" />
Here toolkit is the namespace of WinRTXamlToolkit.Controls:
xmlns:toolkit="using:WinRTXamlToolkit.Controls"
As I didn't set Columns property, it will be the default value which is 0. A value of zero (0) for the Columns property specifies that the column count is computed based on the number of rows and the number of visible child elements that are in the Grid. Since I set Rows to 1, all the items will be put in one row and have the same width.
After this, you may also need to set ItemContainerStyle to make the radio buttons stretch like:
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</GridView.ItemContainerStyle>

WP 8.1 bottom to top infinite scrolling

I have explored ISupportIncrementalLoading and seen MS sample and other examples for infinite scrolling behaviour.
But I want bottom to top scrolling where items are added on top on scrolling bottom to top.
Edit:I have found a workaround for this. I have rotated listview by 180 degree and datatemplate by 180 degree which helped me achieve desired functionality.
<ListView x:Name="GridViewMain" IncrementalLoadingThreshold="2" RenderTransformOrigin="0.5,0.5">
<ListView.RenderTransform>
<RotateTransform Angle="180"></RotateTransform>
</ListView.RenderTransform>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.Resources>
<DataTemplate x:Key="DataTemplateGridViewMain">
<Grid HorizontalAlignment="Stretch" Background="#FF7C1A9B" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<RotateTransform Angle="180"/>
</Grid.RenderTransform>
<TextBlock HorizontalAlignment="Left" Text="{Binding}" VerticalAlignment="Center" FontSize="20" FontFamily="Tempus Sans ITC" />
</Grid>
</DataTemplate>
</ListView.Resources>
<ListView.ItemTemplate>
<StaticResource ResourceKey="DataTemplateGridViewMain" />
</ListView.ItemTemplate>
</ListView>
Is this solution has any perf impact or is there any alternate way to do this?
not sure if this will fit your needs, but I had to do something similar when creating a chat conversation screen, and was able to achieve this using ExtendedListView: https://www.nuget.org/packages/ExtendedListView
We load the most recent items, and use ScrollIntoView(lastMessage) to position the cursor at the bottom. Normally you would use MoreDataRequested event to get items when it scrolls to the bottom, but instead we reversed it and used the PullToRefreshRequested to simulate scrolling to the top, changing the loading template to say "loading more messages".
works pretty well for us, I hope this is helpful!

XAML style is applied to only the first rectangle. How to make it apply to all?

In a Windows 8 (WinRT) app, I am creating my own XAML style to get a dotted rectangle. In the setter for the style, I use Property="StrokeDashArray" Value="1,4". I then create a bunch of rectangles, and then explicitly set the style of those rectangles to this style I created. The first rectangle shows up with a dotted border - but the other two don't. However, if in addition to the Style={StaticResource myDottedStyle} I also specify the StrokeDashArray with each rectangle, then all them correctly show up with dotted borders.
Why is the dotted border only showing up for the first rectangle? How can I create a Style that is applied to all the rectangles without specifying the StrokeDashArray for each of them?
Here is a full code sample. In Windows 8 RTM, create a Blank XAML app project, and replace the Grid in the MainPage.xaml with the following:
<Page.Resources>
<Style x:Key="myDottedStyle" TargetType="Rectangle">
<Setter Property="Stroke"
Value="{StaticResource ApplicationForegroundThemeBrush}"/>
<Setter Property="StrokeThickness" Value="2"/>
<Setter Property="StrokeDashArray" Value="1,4"/>
</Style>
</Page.Resources>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Rectangle Style="{StaticResource myDottedStyle}" Width="40"
HorizontalAlignment="Left"/>
<Rectangle Style="{StaticResource myDottedStyle}" Width="40"
HorizontalAlignment="Center"/>
<Rectangle Style="{StaticResource myDottedStyle}" Width="40"
HorizontalAlignment="Right"/>
</Grid>
Here is a screenshot of the output of this
I found a related question that talks about DataTemplates here but I can't figure out how to translate that into my problem.
You could optimize things a bit by not requiring it to re-draw the rectangle per each instance and substitute for a ContentControl instead since they appear the same but with minor differences. So something for example like;
<Style x:Key="MyDottedStyle" TargetType="ContentControl">
<!-- Add additional Setters Here -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Rectangle Stroke="{StaticResource ApplicationForegroundThemeBrush}"
StrokeThickness="2"
StrokeDashArray="1,4"
Width="40" Height="40"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
Margin="{TemplateBinding Margin}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- And now actually place it on your view -->
<ContentControl Style="{StaticResource MyDottedStyle}" HorizontalAlignment="Center"/>
This will allow you to not only clean things up because you can take your Style template and slap it over into say a Resource Dictionary to reduce clutter, but also makes it a little more efficient since you're not re-drawing your shape every time it's required. Hope this helps! Cheers!