UWP ItemsControl content not stretching as in WPF - c#

I am experiencing some behaviour in a UWP project that I am unable to understand, however my implementations of this in WPF work as expected.
If I have a StackPanel, and insert some grids, the grids stretch to fill the width of the StackPanel as expected.
<StackPanel Grid.Row="1">
<Grid Background="Blue">
<TextBlock>Item 1</TextBlock>
</Grid>
<Grid Background="Green">
<TextBlock>Item 2</TextBlock>
</Grid>
<Grid Background="Red">
<TextBlock>Item 3</TextBlock>
</Grid>
<Grid Background="Pink">
<TextBlock>Item 4</TextBlock>
</Grid>
</StackPanel>
However, once I try to introduce binding and collections, this behaviour stops happening.
<ItemsControl ItemsSource="{Binding Devices}" Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Background="Violet">
<TextBlock>Hello</TextBlock>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I have found similar issues reported dating back to 2010, but none of the solutions have worked thus far. I have also found issues reported here for UWP Grid generally, used in other contexts. I have tried using a ListBox (which behaves the same in this regard), setting HorizontalContentAlignment, using styles as Silverlight users seem to have found joy in doing so, and changing how I express my ItemsControl. Nothing has worked thus far, and I am feeling that there is something wrong with XAML in UWP as I don't seem to experience any issues at all in WPF. Is there a known problem, or am I simply going about this the wrong way?
I simply want the child grid to stretch to fill horizontally. I should mention:
It does behave if I wrap the grid in a ViewBox, but this is not desirable as it has other adverse effects.
If I click on everything down the hierarchy in XAML, starting at ItemsControl, the box rendered around this selection is full width all the way down to (excluding) DataTemplate. DataTemplate and Grid show a tight-bound box, but if I look in the property inspector the Grid has its horizontal alignment as stretch. This leads me to believe that the DataTemplate is wrapping the grid with something that doesn't have a HorizontalAlignment="Stretch", and I have no known mechanism to change this.

This behaviour seems to only appear in the designer of Visual Studio and Expression Blend. Once built and executing on both Phone and Desktop, everything appears to render correctly.
I've generally had very good experiences with the designer, and did not expect this to be the case. Had I just ignored the designer and progressed, I would have realised this sooner. I have reported this issue via the VisualStudio feedback tool.

Related

Printing custom usercontrols with MVVM WPF

I have a view where I display a bunch of trading cards. Each card is a user control, and these are all displayed in a window. There are 4 cards to a row for however many rows are in some observable collection of cards. I want to be able to print this. I have done this in the past by recreating all the UI elements in the code-behind, but I want to rewrite this using MVVM, and even though I could still do this method in MVVM, it doesn't seem to be the cleanest solution. Does anyone know a simpler way to achieve this? Here is my XAML code for the Window of what I want to print:
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding StateManager.Cards}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type cardModels:AttackCard}">
<StackPanel>
<cardViews:AttackCardControl />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type cardModels:EquipmentCard}">
<StackPanel>
<cardViews:EquipmentCardControl />
</StackPanel>
</DataTemplate>
...
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="960"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
As you can see, I have an ItemsControl that contains all the cards within a wrap panel with a fixed Width. The width of each Card is exactly 240, so this allows exactly 4 cards to fit per row. The Data Templates are for the displaying the different types of cards that all inherit from a Card class and are in an ObservableCollection. Any one have any ideas on how to print this? From my past program, I have also learned that only 2 rows will fit on a sheet of paper and it must be printed at a 90 degree angle (landscape view). Thank you for any help!

Too much spacing between StackPanel items in Windows Store app

I'd like to arrange some TextBlocks horizontally without any margins. I can see that my TextBlock is as small as it should be, but for some reason a lot of space is added around it. I think it has something to do with the ListView or its styling, but I don't know what.
I have a following layout:
<ListView Width="Auto" SelectionMode="None" Background="#654321" ItemsSource="{Binding}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Border Background="Black">
<TextBlock Text="{Binding}" Margin="0,0,0,0"/>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
<x:String>A</x:String>
<x:String>B</x:String>
<x:String>C</x:String>
<x:String>D</x:String>
<x:String>E</x:String>
</ListView>
What you need to change is the ItemContainerStyle. You can get the Style from here.
The big thing to notice is that the default Margin of the Style is:
<Setter Property="Margin" Value="0,0,18,2"/>
Which explains the large gap. Change it to:
<Setter Property="Margin" Value="0,0,0,2"/>
And that should help solve your issue.
One last thing to note is that they also have a default ContentMargin="4" (if using the ListViewItemsPresenter) or a bunch of Margins of 4 spread throughout the style (especially on the Borders), which you may need to change as well.
The other way to look at it - ListView is really designed as a control where you can tap, select, drag and otherwise interact with the items. I think if you want to remove all the features that ensure the sizes are touchable with fat fingers - you might just be better off using something like the base ItemsControl or ListBox which might not have these limitations. If you get rid of all the margins and leave your items so small - there's no point in using the ListView and it will just complicate things and make performance bad.

Foreground and few other styles changing when Flyout displayed at the second time

I got stuck with a strange behavior. While I show native Flyout at the second time, foreground style and some other styles changing for the whole app. After some searching I found the same problem in this MSDN topic, but topic is locked without any solution or answer. The sample and screenshots is the same for my my problem.
Solution found. I had Flyout directly in ListView and it cause such problems:
<ListView ...>
<FlyoutBase.AttachedFlyout>
...
</FlyoutBase.AttachedFlyout>
</ListView>
After moving Flyout to the ItemTemplate, the problem is gone:
<ListView ...>
<ListView.ItemTemplate>
<DataTemplate>
<Grid ...>
<FlyoutBase.AttachedFlyout>
...
</FlyoutBase.AttachedFlyout>
</Grid>
<DataTemplate>
</ListView.ItemTemplate>
</ListView>

How to implement parallax background on a grouped GridView inside Semantic Zoom

I'm trying to implement a nice-looking horizontally scrolled gridview inside my app. I have already implemented it using the Q42.WinRT library like this:
<Canvas>
<StackPanel Orientation="Horizontal" Height="768">
<StackPanel.RenderTransform>
<CompositeTransform
TranslateX="{Binding ElementName=MyScrollViewer, Path=HorizontalOffset, Converter={StaticResource ParallaxConverter}}" />
</StackPanel.RenderTransform>
<Image Source="/Assets/3.jpg" Width="1366" Stretch="UniformToFill"/>
<Image Source="/Assets/1.jpg" Stretch="UniformToFill"/>
<Image Source="/Assets/2.jpg" Stretch="UniformToFill"/>
</StackPanel>
</Canvas>
<ScrollViewer
x:Name="MyScrollViewer"
HorizontalScrollMode="Enabled"
HorizontalScrollBarVisibility="Auto"
VerticalScrollMode="Disabled"
VerticalAlignment="Center"
Height="768">
<GridView>
//...my gridview goes here
</GridView> </ScrollViewer>
Everything works fine, however in my app I need to use semantic zoom, and I found that semantic zoom does NOT WORK properly when put inside a ScrollViewer.
Generally all the solutions for parallactic backgrounds that I found on the internet implement some kind of functionality over a scrollviewer, which is unfortunate for me as I cannot use it.
Can anybody think of another way to achieve the desired effect?
Generally putting GridViews inside a ScrollViewer is not a great idea since they already have ScrollViewers inside of them...
You should put your 2 GridViews inside a SemanticZoom.
Perhaps you could edit the template for your GridView and put a parallax background in there - perhaps as a Canvas with some content that responds to the ViewChanged events on the GridView.
EDIT*
You inspired me to try to write a ParallaxBackgroundBehavior for the Toolkit. :)
You can see an early version here. There is also a sample included.

Hide control when another control overlaps it

I am having pretty big problem with windows forms controls hosted in WPF. When, for example, user scrolls the window, the hosted control goes on top of the window, although it should be hidden.
I know this is known problem, and default behavior of hosted controls, but I think it can be solved if control's visibility is somehow binded with: whether other controls overlap it, or not. If other controls are overlapping, it should become Collapsed or Hidden, if not, it should be Visible.
I made some kind of solution for this, but I did it on ScrollChanged event of a ScrollViewer and it works only in special situations. If somebody knows how to achieve that with binding, so it can be applied to any hosted control, please share your ideas.
For this same problem, we implemented something curious...
Windows forms host is unaffected by Z-order so scroll viewer wont be able to partially hide/ clip it for the area which is visible under the scrollviewer.
So we had two options...
Use Windows form host to host rest of the WPF UI in it which means we reverse the ownership of the UI. The WindowsFormsHost must host all the UI in it having a WinForms based scroll viewer which in turn will host the WPF UI.
Implement a scroll offset for calculated height of the windows forms host and when user scrolls add this offset to the scrollviewer's position and hide the windforms host yourself (Visibility = Hidden and NOT Collapsed). This way it gives an effect that you cannot partially scroll a winforms host but that scroll it completely off the scroll viewer. And because winformshost is Hidden (not collapsed) it continues to occupy that much height inside the invisible area under the scroll viewer (thereby maintaining its scroll position).
Let me know if this guides you in correct direction.
You can do a little trick. When you declare an WindowsFormsHost, it's parent is first HWND component. Usually it's root window. So, clip area for controls is whole window.
I'll show an example with WPF ScrollViewer.
<Window>
<Grid>
<ScrollViewer Margin="20,50">
<ItemsControl ItemsSource="{StaticResource StringArray}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<WindowsFormsHost>
<wf:Button />
</WindowsFormsHost>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Window>
In this case behaviour will be like you described. Buttons will be out of ScrollViewer bounds.
But there's a way to create "intermediate" HWND item to clip WinForms area over ScrollViewer. Just place another WindowsFormsHost with ElementHost like below:
<Grid>
<WindowsFormsHost Margin="20,50">
<ElementHost x:Name="This is clip container">
<ScrollViewer>
<ItemsControl ItemsSource="{StaticResource StringArray}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<WindowsFormsHost>
<wf:Button />
</WindowsFormsHost>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</ElementHost>
</WindowsFormsHost>
</Grid>
Now clip area for buttons is ElementHost and WinForms Buttons will be clipped by it on scrolling.
Also you can create ControlTemplate for ContentContol and reuse it where you need it.
<ControlTemplate x:Key="ClipConteiner" TargetType="{x:Type ContentControl}">
<WindowsFormsHost>
<ElementHost>
<ContentPresenter />
</ElementHost>
</WindowsFormsHost>
</ControlTemplate>
<Grid>
<ContentControl Template="{StaticResource ClipConteiner}" Margin="20,50">
<ScrollViewer>
<ItemsControl ItemsSource="{StaticResource StringArray}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<WindowsFormsHost>
<wf:Button />
</WindowsFormsHost>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</ContentControl>
</Grid>

Categories