In UWP, is there a way to make columns wrap beneath eachother? - c#

In my UWP project, i have a page containing a grid with 4 columns that is resonably wide.
When the screen gets smaller (less wide), the columns get cut off (unreachable as they are out of view)
Is there a possible way to make the columns wrap (preferably the third and fourth column at the same time) to have the third and fourth columns beneath the first and second?
I'd like a hardcoded values-less approach the best.
Note: i do not have to keep using the Grid, if there is an obviously better approach to this with i.e. a RelativeView i'd be in for that as well

I think you may use the AdaptiveTrigger to change it when the width be changed.
And change the Grid to WrapGrid or do some thing to make Grid show best.
To know when should use the narrow UI , you should add some code just like this:
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="The min size" />
</VisualState.StateTriggers>
When the windows size more that the min size , it will run the VisualState.
The code is below:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="wideView">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="narrowView">
<VisualState.Setters>
<Setter Target="Grid1.(Grid.RowSpan)" Value="1"></Setter>
<Setter Target="Grid1.(Grid.ColumnSpan)" Value="2"></Setter>
<Setter Target="Grid2.(Grid.RowSpan)" Value="1"></Setter>
<Setter Target="Grid2.(Grid.Row)" Value="1"></Setter>
<Setter Target="Grid2.(Grid.ColumnSpan)" Value="2"></Setter>
<Setter Target="Grid2.(Grid.Column)" Value="0"></Setter>
</VisualState.Setters>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="177*"/>
<RowDefinition Height="143*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid x:Name="Grid1" Margin="10,10,10,10" Background="Black" Grid.RowSpan="2" ></Grid>
<Grid x:Name="Grid2" Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" Margin="10,10,10,10" Background="Black" ></Grid>
</Grid>
Another way is use SizeChange that you should give the Grid a name and I want name the Grid to Grid.
<Grid >
<Grid x:Name="Grid">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid Margin="10,10,10,10" Width="100" Height="100" Background="Black" Grid.RowSpan="2" ></Grid>
<Grid Grid.Column="1" Grid.Row="0" Margin="10,10,10,10" Width="100" Height="100" Background="Black" ></Grid>
</Grid>
<GridView x:Name="GridView" Visibility="Collapsed">
</GridView>
</Grid>
And I add SizeChange in Initialize.
public MainPage()
{
this.InitializeComponent();
SizeChanged += MainPage_SizeChanged;
}
And I will add a property which set the min width.
When the windows in the min width that can change the Grid1 and Grid2's Grid.Row property.
private void MainPage_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (e.NewSize.Width < MinWidht)
{
if (_grid)
{
_grid = false;
Grid.Visibility = Visibility.Collapsed;
var children = Grid.Children.ToList();
Grid.Children.Clear();
GridView.ItemsSource = children.ToList();
GridView.Visibility = Visibility.Visible;
Grid.Children.Clear();
}
}
else
{
if (!_grid)
{
// change to GridView to Grid
}
}
}
private const double MinWidht = 700;
private bool _grid = true;
See: http://www.c-sharpcorner.com/article/adaptive-grid-view-control-in-uwp-with-xaml-and-c-sharp/

Related

UWP Image overflow inside button

I'm trying to stretch an image inside a Button which is inside a stackpanel and a grid but it doesn't works. On mobile size it works very well but when the app is for an Desktop it doesn't work anymore, we can see that the image overflows.
And what it looks like on desktop
My code:
<StackPanel x:Name="g5" Grid.Column="1" Grid.Row="1" Padding="20" Orientation="Vertical" >
<TextBlock Text="Site" FontSize="20"/>
<Button x:Name="websiteButton" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0" Background="#fc0">
<Image x:Name="websiteImage" Source="Assets/website.png" NineGrid="0" Margin="20,20,20,20"/>
</Button>
</StackPanel>
Someone can tell me what is wrong and how i can stretch the image inside the button ? Btw it's a .png file.
Thanks everyone !!
Stack Panel with Vertical orientation does not impose any limits on the Children in terms of their height. It just ensures that they are stacked one on top of another. This means, that on Desktop the Button gets large width and therefore the image grows vertically to. One way to prevent this is to set MaxHeight of the Button or of the Image inside of it.
A better solution would be to use a Grid:
<Grid x:Name="g5" Height="200" HorizontalAlignment="Stretch" Padding="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="Site" FontSize="20"/>
<Button Grid.Row="1" x:Name="websiteButton" HorizontalAlignment="Stretch" Margin="0" Background="#fc0">
<Image x:Name="websiteImage" Source="/Assets/Square150x150Logo.png" NineGrid="0" Margin="20,20,20,20"/>
</Button>
</Grid>
The second row of the Grid has "*" height, which means that it will grow to fill available space. This will limit the height of the button. The default Stretch value of the image is Uniform, which will ensure the image will look good inside the button.
#Romasz and #MZetko are right. But for layout targeting different device platform, my suggestion is that you can also use VisualStateManager to set the Width and Height properties for different app window's size for example like this:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
<!--for desktop-->
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="websiteButton.Width" Value="300" />
<Setter Target="websiteButton.Height" Value="300" />
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
<!--for mobile-->
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="websiteButton.Width" Value="150" />
<Setter Target="websiteButton.Height" Value="150" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

Resolution is strange on second animation via template

In my Universal Windows 10 app, I have an animation that shrinks a custom control whose looks is applied via a template. It works as expected the first time it is run. The second time it is run, the start of the animation is rendered in a horrible resolution, apparently tainted by the previous run:
First time is on the left; second time on the right.
If, instead of using a custom control with a template, I hardcode everything in XAML, the problem doesn't occur.
If I grow rather than shrink the target, the problem doesn't occur.
Let me start with the non-templated version, which is shorter and easier to read than the templated version:
<Page
x:Class="TestApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="AnimationStates">
<VisualState x:Name="Show">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="transform"
Storyboard.TargetProperty="ScaleX"
To="0.1"
BeginTime="0:00:2"
Duration="0:00:1">
</DoubleAnimation>
<DoubleAnimation
Storyboard.TargetName="transform"
Storyboard.TargetProperty="ScaleY"
To="0.1"
BeginTime="0:00:2"
Duration="0:00:1">
</DoubleAnimation>
</Storyboard>
</VisualState>
<VisualState x:Name="Hide" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="16"
FontSize="122"
Text="Q">
<TextBlock.RenderTransform>
<ScaleTransform x:Name="transform" />
</TextBlock.RenderTransform>
</TextBlock>
<Button
Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="16"
Content="Animate!"
Click="OnAnimateClicked" />
</Grid>
</Page>
The code-behind is as follows:
public sealed partial class MainPage
{
public MainPage()
{
InitializeComponent();
}
private void OnAnimateClicked(object sender, RoutedEventArgs e)
{
VisualStateManager.GoToState(this, "Hide", useTransitions: false);
VisualStateManager.GoToState(this, "Show", useTransitions: true);
}
}
This works fine every time. But. Instead of applying the ScaleTransform to the TextBlock's RenderTransform directly, I have a custom control with a template applied. For illustration purposes we can use a custom control that is little more than a placeholder:
public sealed class CustomControl : Control
{
}
Then change the XAML to replace the TextBlock with a CustomControl, applying a template to the CustomControl:
<Page
x:Class="TestApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestApp">
<Grid>
<Grid.Resources>
<Style TargetType="local:CustomControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:CustomControl">
<Grid>
<TextBlock Text="Q" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="AnimationStates">
<VisualState x:Name="Show">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="transform"
Storyboard.TargetProperty="ScaleX"
To="0.1"
BeginTime="0:00:2"
Duration="0:00:1">
</DoubleAnimation>
<DoubleAnimation
Storyboard.TargetName="transform"
Storyboard.TargetProperty="ScaleY"
To="0.1"
BeginTime="0:00:2"
Duration="0:00:1">
</DoubleAnimation>
</Storyboard>
</VisualState>
<VisualState x:Name="Hide" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<local:CustomControl
HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="16"
FontSize="122">
<local:CustomControl.RenderTransform>
<ScaleTransform x:Name="transform" />
</local:CustomControl.RenderTransform>
</local:CustomControl>
<Button
Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="16"
Content="Animate!"
Click="OnAnimateClicked"/>
</Grid>
</Page>
The first time I click the Animate button, this works exactly like the first version. The second and subsequent times, the initial animation rendering uses the really coarse resolution shown on the right:
The coarseness seems to be proportional to the shrinkage factor. Is this a bug of some sort (a failed optimization?), or is my understanding of templates flawed?

Pivot control customization on UWP

Basically I need to customize the pivot control on my uwp app and I use the style of pivot from windows phone 8.1. And it looks like this eventually(the yellow part is the content of the pivot item, I just use color to differentiate the header and the content)
But right now it does not meet the require of the original design. So I have two questions here:
1.How do I limit user flick the pivot in one direction? For example, users could only flick the control from left to right because the yellow content part will move to left and cover the header if the pivot is flicked from the right to the left. The content, which is the yellow part, will move entirely along with your finger and the other covered pivot header will be shown because the yellow part moves away, as you can see on the image. This is the reason why I care about the swiping direction because if you swipe left, the yellow part will covers part of the header before the gesture is done(which is not showing up in the image).
2.How to change the foreground color of the unselected pivotitem header? Right now as you can see, during the flicking process, the yellow content part will move away and the unselected header will be shown. That looks weird and it is not a good design at all. The unselected header is suppose to be transparent or be the same as the background color of the page.
Here is the code of the style:
<Style x:Key="PivotStyle1" TargetType="Pivot">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Foreground" Value="{ThemeResource PivotForegroundThemeBrush}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Pivot">
<Grid x:Name="RootElement" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Orientation">
<VisualState x:Name="Portrait">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" Storyboard.TargetName="TitleContentControl">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotPortraitThemePadding}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Landscape">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" Storyboard.TargetName="TitleContentControl">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotLandscapeThemePadding}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentControl x:Name="TitleContentControl" ContentTemplate="{TemplateBinding TitleTemplate}" Content="{TemplateBinding Title}" Style="{StaticResource PivotTitleContentControlStyle}"/>
<ScrollViewer x:Name="ScrollViewer" HorizontalSnapPointsAlignment="Center" HorizontalSnapPointsType="MandatorySingle" HorizontalScrollBarVisibility="Hidden" Margin="{TemplateBinding Padding}" Grid.Row="1" Template="{StaticResource ScrollViewerScrollBarlessTemplate}" VerticalSnapPointsType="None" VerticalScrollBarVisibility="Disabled" VerticalScrollMode="Disabled" VerticalContentAlignment="Stretch" ZoomMode="Disabled">
<PivotPanel x:Name="Panel" VerticalAlignment="Stretch">
<PivotHeaderPanel x:Name="Header">
<PivotHeaderPanel.RenderTransform>
<CompositeTransform x:Name="HeaderTranslateTransform" TranslateX="0"/>
</PivotHeaderPanel.RenderTransform>
</PivotHeaderPanel>
<ItemsPresenter x:Name="PivotItemPresenter">
<ItemsPresenter.RenderTransform>
<TranslateTransform x:Name="ItemsPresenterTranslateTransform" X="0"/>
</ItemsPresenter.RenderTransform>
</ItemsPresenter>
</PivotPanel>
</ScrollViewer>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And the XAML code for the pivot control:
<Pivot Style="{StaticResource PivotStyle1}">
<Pivot.HeaderTemplate>
<DataTemplate>
<Grid Height="auto">
<Grid.RowDefinitions>
<RowDefinition Height="21*"/>
<RowDefinition Height="299*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="19*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding}"
Margin="14,50,9,-120"
Grid.Row="1"
HorizontalAlignment="Center"
FontSize="48"
FontFamily="ms-appx:NotoSansCJKsc-Black.otf#Noto Sans CJK SC"
TextWrapping="Wrap"
LineStackingStrategy="BlockLineHeight"
LineHeight="49" Width="48"
Height="auto"/>
</Grid>
</DataTemplate>
</Pivot.HeaderTemplate>
<PivotItem Header="评论" Margin="83,-47,0,0" Background="Yellow">
<Grid>
<ListView x:Name="listview" d:LayoutOverrides="TopPosition, BottomPosition" ItemTemplate="{StaticResource GroupTemplate}" ItemsSource="{Binding Groups}" Margin="10,0,0,0"/>
</Grid>
</PivotItem>
<PivotItem Header="转发" Margin="93,-47,0,0" Background="Yellow">
<Grid>
<ListView x:Name="listview2" d:LayoutOverrides="TopPosition, BottomPosition" ItemTemplate="{StaticResource GroupTemplate}" ItemsSource="{Binding Groups}"/>
</Grid>
</PivotItem>
</Pivot>
For your first question, you have customize the style of the Pivot control, your gesture shown above works fine on the mobile emulator, but not on the local machine. This is the problem about ManipulationMode in the design of a Pivot control. Pivot control's Gesture is achieved inside it's style, so it is possible to manipulate it in one direction, but we need to find the key point in the style.
You can use Manipulation to do this. You can modify your style of Pivot control like this:
<PivotPanel x:Name="Panel" VerticalAlignment="Stretch">
<PivotHeaderPanel x:Name="Header" ManipulationMode="None">
<PivotHeaderPanel.RenderTransform>
<CompositeTransform x:Name="HeaderTranslateTransform" TranslateX="0" />
</PivotHeaderPanel.RenderTransform>
</PivotHeaderPanel>
<ItemsPresenter x:Name="PivotItemPresenter" ManipulationMode="None">
<ItemsPresenter.RenderTransform>
<TranslateTransform x:Name="ItemsPresenterTranslateTransform" X="0" />
</ItemsPresenter.RenderTransform>
</ItemsPresenter>
</PivotPanel>
and use this Pivot control like this:
<Pivot Style="{StaticResource PivotStyle1}" x:Name="myPivot" ManipulationMode="TranslateX" ManipulationStarting="OnStarting" ManipulationCompleted="OnCompleted">
...
</Pivot>
And the code behind:
public double pointx1;
private void OnCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
{
var pointx2 = Window.Current.CoreWindow.PointerPosition.X;
if (pointx2 > pointx1)
{
if (myPivot.SelectedIndex == 0)
myPivot.SelectedIndex = 1;
else
myPivot.SelectedIndex = 0;
}
else
return;
}
private void OnStarting(object sender, ManipulationStartingRoutedEventArgs e)
{
pointx1 = Window.Current.CoreWindow.PointerPosition.X;
}
Here is also a workaround method to solve this problem, consider that there is no manipulation in the style of Pivot, you can achieve this using PointerPoint you can modify your style of Pivot control like this:
<PivotPanel x:Name="Panel" VerticalAlignment="Stretch" ManipulationMode="None">
<PivotHeaderPanel x:Name="Header">
<PivotHeaderPanel.RenderTransform>
<CompositeTransform x:Name="HeaderTranslateTransform" TranslateX="0" />
</PivotHeaderPanel.RenderTransform>
</PivotHeaderPanel>
<ItemsPresenter x:Name="PivotItemPresenter">
<ItemsPresenter.RenderTransform>
<TranslateTransform x:Name="ItemsPresenterTranslateTransform" X="0" />
</ItemsPresenter.RenderTransform>
</ItemsPresenter>
</PivotPanel>
and use this Pivot control like this:
<Pivot Style="{StaticResource PivotStyle1}" PointerReleased="OnPointerExited" PointerPressed="OnPointerPressed" x:Name="myPivot">
...
</Pivot>
And the code behind:
public PointerPoint pointer1;
private void OnPointerExited(object sender, PointerRoutedEventArgs e)
{
var pointer2 = e.GetCurrentPoint(myPivot);
var position1x = pointer1.Position.X;
var position2x = pointer2.Position.X;
if (position2x > position1x)
{
if (myPivot.SelectedIndex == 0)
myPivot.SelectedIndex = 1;
else
myPivot.SelectedIndex = 0;
}
else
return;
}
private void OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
pointer1 = e.GetCurrentPoint(myPivot);
}
And for your second question, as #ganchito55 said, you can modify the style of PivotHeaderItem.
Update:
If you just don't want to see the header of the other item when you manipulate it, you can modify the PivotHeaderItem like this:
......
<Setter Property="FontWeight" Value="{ThemeResource PivotHeaderItemThemeFontWeight}" />
<Setter Property="CharacterSpacing" Value="{ThemeResource PivotHeaderItemCharacterSpacing}" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="Transparent" />
<Setter Property="Padding" Value="{ThemeResource PivotHeaderItemMargin}" />
<Setter Property="Height" Value="48" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="IsTabStop" Value="False" />
......

Set Dimensions of RelativePanel's Children proportional to that of parent view

I am new to Windows Runtime programming and decided to get stuck in ahead of the release of Windows 10.
I am trying to design an adaptive page UI that looks something like as follows,
There is header "stuff" at the top and beneath it I want two columns, each with a textblock header and below it, a listview. The listview could be arbitraryheight and so the parent of the two blocks should, I think, be a scrollviewer.
On mobile however, this UI won't work as the screen is far to narrow, and so I would like to use a visualstate to rearrange the page so it looks as follows,
As you can see, the need for a scrollviewer is apparent to wrap this section. the "Other stuff" at the top should stay fixed however so it can be seen all the time.
I have tried a number of approaches to achieve this but haven't been able to manage it. What I currently have is this:
//.... Other Stuff ......
<ScrollViewer x:Name="SummaryScrollViewer" Grid.Row="2" HorizontalScrollBarVisibility="Disabled"
HorizontalScrollMode="Disabled" VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto" HorizontalContentAlignment="Center">
<RelativePanel x:Name="SummaryRelativePanel">
<Grid x:Name="lCol" Width="{Binding ActualWidth, ElementName=SummaryRelativePanel}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="lcolHead" Grid.Row="0" Text="TextBlock:"/>
<ListView x:Name="lcolList" Grid.Row="1">
</ListView>
</Grid>
<StackPanel x:Name="rCol" Orientation="Vertical" RelativePanel.RightOf="lCol">
<TextBlock x:Name="rcolHead" Text="TextBlock:"/>
<ListView x:Name="rcolList" Height="Auto">
</ListView>
</StackPanel>
</RelativePanel>
</ScrollViewer>
As you can see, I have tried to make the contents of each column both a stackpanel, and a grid, but I haven't been able to set the width of them to be, in "desktop view", half that of the containing relative panel, which should fill the full width of the screen, and in "mobile view" they should fill the full width of the parent.
I have found answers on how to bind the width to the ActualWidth property of the parent element as can be seen in the snippet, and this works, but I can't seem to make the two columns fill half of the parent each.
I wanted to use a RelativePanel so I can use the viewstate to change the properties of the right hand column to be either RightOf="LeftCol" or Below="LeftCol", and the widths should then be updated too to fill the width required.
Using a grid Should also be possible, define a 4x4 grid where in desktop the bottom two are collapse, or in mobile the right two are collapsed, but I was under the impression that this is the precise usecase the relativepanel was intended for.
In all examples of relativepanel they use relativepanel to move programmer defined with/height elements such as rectangles RelativePanel class.
It would also be possible to manually set ActualWidth of each column programatically from the code-behind but I don't know how to query which visual state the app/page is currently in to figure out how wide and where each column should be.
Any help and advice on what the "best" way to achieve such a thing would be would be greatly appreciated.
Here we go, let's begin that the bugs (or things I think are bugs)
1.- If I set a control with binding to the RelativePanel ActualWidth it just takes the first time, I mean, if I expand the window the control does not resize, so bug?
So let's do it with Grid:
<Grid x:Name="LayoutRoot" Background="Red" >
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="WindowSizeStates" >
<VisualState x:Name="SmallScreen" >
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="ContentLayoutRoot.Background" Value="Green"/>
<Setter Target="ContentLayoutRoot.RowDefinitions[0].Height" Value="100"/>
<Setter Target="ContentLayoutRoot.RowDefinitions[1].Height" Value="400"/>
<Setter Target="ContentLayoutRoot.RowDefinitions[2].Height" Value="100"/>
<Setter Target="ContentLayoutRoot.RowDefinitions[3].Height" Value="400"/>
<Setter Target="ContentLayoutRoot.ColumnDefinitions[0].Width" Value="1*"/>
<Setter Target="ContentLayoutRoot.ColumnDefinitions[1].Width" Value="0"/>
<Setter Target="SubHeaderOneLayout.(Grid.Row)" Value="0"/>
<Setter Target="ContentOneLayout.(Grid.Row)" Value="1"/>
<Setter Target="SubHeaderTwoLayout.(Grid.Row)" Value="2"/>
<Setter Target="ContentTwoLayout.(Grid.Row)" Value="3"/>
<Setter Target="SubHeaderTwoLayout.(Grid.Column)" Value="0"/>
<Setter Target="ContentTwoLayout.(Grid.Column)" Value="0"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="WideScreen">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1000" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="ContentLayoutRoot.Background" Value="Purple"/>
<Setter Target="ContentLayoutRoot.RowDefinitions[0].Height" Value="100"/>
<Setter Target="ContentLayoutRoot.RowDefinitions[1].Height" Value="900"/>
<Setter Target="ContentLayoutRoot.RowDefinitions[2].Height" Value="0"/>
<Setter Target="ContentLayoutRoot.RowDefinitions[3].Height" Value="0"/>
<Setter Target="ContentLayoutRoot.ColumnDefinitions[0].Width" Value="0.5*"/>
<Setter Target="ContentLayoutRoot.ColumnDefinitions[1].Width" Value="0.5*"/>
<Setter Target="SubHeaderOneLayout.(Grid.Row)" Value="0"/>
<Setter Target="ContentOneLayout.(Grid.Row)" Value="1"/>
<Setter Target="SubHeaderTwoLayout.(Grid.Row)" Value="0"/>
<Setter Target="ContentTwoLayout.(Grid.Row)" Value="1"/>
<Setter Target="SubHeaderTwoLayout.(Grid.Column)" Value="1"/>
<Setter Target="ContentTwoLayout.(Grid.Column)" Value="1"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid x:Name="HeaderLayout" VerticalAlignment="Top" Height="32">
<TextBlock Text="Other Stuff" HorizontalAlignment="Center"/>
</Grid>
<ScrollViewer Grid.Row="1">
<Grid x:Name="ContentLayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="900"/>
<RowDefinition Height="0"/>
<RowDefinition Height="0"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.5*"/>
</Grid.ColumnDefinitions>
<Grid x:Name="SubHeaderOneLayout" >
<TextBlock Text="Sub Header One" HorizontalAlignment="Center"/>
</Grid>
<Grid x:Name="SubHeaderTwoLayout" Grid.Column="1">
<TextBlock Text="Sub Header Two" HorizontalAlignment="Center"/>
</Grid>
<Grid x:Name="ContentOneLayout" Background="Orange" Grid.Row="1">
<TextBlock Text="ContentOne Layout" HorizontalAlignment="Center"/>
</Grid>
<Grid x:Name="ContentTwoLayout" Background="Orange" Grid.Row="1" Grid.Column="1">
<TextBlock Text="ContentOne Layout" HorizontalAlignment="Center"/>
</Grid>
</Grid>
</ScrollViewer>
I could try to make it with Relative Panel but involves events, and more things, tell me if it is enough.
And, well the triggers I discovered by myself, you can get more info in my article in codeproject

How do I call an MvxCommand/ICommand when selecting an item from a Grid?

I am enjoying the N+1DaysOfMVVMCross but I am stuck on Day 5 (Sort of a day 2 and day 5 combo)...
I used day 2 to develop a grid view UI and wanted to use the day 5 info to add a Command that will open a secondary view when an item is selected from the grid. The Command code in the ViewModel is never executed (though it does execute from a button).
I think the issue is more related to WPF/XAML but thought I would reference MVVMCross as this is where I hit the road block.
Thanks for any help/tips/direction
How about some source code...
From the view model, sorry for the list initialization I'm slowly working through this.
using Cirrious.MvvmCross.ViewModels;
using System.Collections.Generic;
using TeleBacteriology.Core.Services;
namespace TeleBacteriology.Core.ViewModels
{
public class WorklistViewModel : MvxViewModel
{
public WorklistViewModel(IWorklistItemService service)
{
var newList = new List<WorklistItem>();
WorklistItem newWorklistItem = service.CreateNewWorklistItem("201401250001", "http://placekitten.com/301/301");
newList.Add(newWorklistItem);
newWorklistItem = service.CreateNewWorklistItem("201401250002", "http://placekitten.com/302/302");
newList.Add(newWorklistItem);
newWorklistItem = service.CreateNewWorklistItem("201401250003", "http://placekitten.com/303/303");
newList.Add(newWorklistItem);
newWorklistItem = service.CreateNewWorklistItem("201401250004", "http://placekitten.com/304/304");
newList.Add(newWorklistItem);
newWorklistItem = service.CreateNewWorklistItem("201401250005", "http://placekitten.com/305/305");
newList.Add(newWorklistItem);
newWorklistItem = service.CreateNewWorklistItem("201401250006", "http://placekitten.com/306/306");
newList.Add(newWorklistItem);
newWorklistItem = service.CreateNewWorklistItem("201401250007", "http://placekitten.com/307/307");
newList.Add(newWorklistItem);
newWorklistItem = service.CreateNewWorklistItem("201401250008", "http://placekitten.com/308/308");
newList.Add(newWorklistItem);
newWorklistItem = service.CreateNewWorklistItem("201401250009", "http://placekitten.com/309/309");
newList.Add(newWorklistItem);
newWorklistItem = service.CreateNewWorklistItem("201401250010", "http://placekitten.com/310/310");
newList.Add(newWorklistItem);
Worklist = newList;
}
private List<WorklistItem> _worklist;
public List<WorklistItem> Worklist
{
get { return _worklist; }
set { _worklist = value; RaisePropertyChanged(() => Worklist); }
}
private MvxCommand _detailsCommand;
public System.Windows.Input.ICommand DetailsCommand
{
get
{
_detailsCommand = _detailsCommand ?? new MvxCommand(DoDetailsCommand);
return _detailsCommand;
}
}
private void DoDetailsCommand()
{
ShowViewModel<PlateDetailsViewModel>();
}
}
}
The XAML for the view:
<common:LayoutAwarePage
x:Name="pageRoot"
x:Class="TeleBacteriology.Store.Views.WorklistView"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TeleBacteriology.Store.Views"
xmlns:common="using:TeleBacteriology.Store.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<!-- Collection of items displayed by this page -->
<CollectionViewSource
x:Name="itemsViewSource"
Source="{Binding Worklist}"/>
<DataTemplate x:Key="Worklist250x250ItemTemplate">
<Grid HorizontalAlignment="Left" Width="250" Height="250">
<Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
<Image Source="{Binding ImageUrl}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
</Border>
<StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
<TextBlock Text="{Binding AccessionNum}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="60" Margin="15,0,15,0"/>
<TextBlock Text="{Binding ImageUrl}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
</StackPanel>
</Grid>
</DataTemplate>
<DataTemplate x:Key="Worklist80ItemTemplate">
<Grid Margin="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}" Width="60" Height="60">
<Image Source="{Binding ImageUrl}" Stretch="UniformToFill"/>
</Border>
<StackPanel Grid.Column="1" Margin="10,0,0,0">
<TextBlock Text="{Binding AccessionNum}" Style="{StaticResource ItemTextStyle}" MaxHeight="40"/>
<TextBlock Text="{Binding ImageUrl}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap"/>
</StackPanel>
</Grid>
</DataTemplate>
<!-- TODO: Delete this line if the key AppName is declared in App.xaml -->
<x:String x:Key="AppName">My Application</x:String>
</Page.Resources>
<!--
This grid acts as a root panel for the page that defines two rows:
* Row 0 contains the back button and page title
* Row 1 contains the rest of the page layout
-->
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Horizontal scrolling grid used in most view states -->
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemsGridView"
AutomationProperties.Name="Items"
TabIndex="1"
Grid.RowSpan="2"
Padding="116,136,116,46"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
ItemTemplate="{StaticResource Worklist250x250ItemTemplate}"
SelectionMode="None"
IsSwipeEnabled="false"
SelectedItem="{Binding DetailsCommand}"/>
<!-- Vertical scrolling list only used when snapped -->
<ListView
x:Name="itemListView"
AutomationProperties.AutomationId="ItemsListView"
AutomationProperties.Name="Items"
TabIndex="1"
Grid.Row="1"
Visibility="Collapsed"
Margin="0,-10,0,0"
Padding="10,0,0,60"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
SelectedItem="{Binding DetailsCommand}"
ItemTemplate="{StaticResource Worklist80ItemTemplate}"
SelectionMode="None"
IsSwipeEnabled="false"/>
<!-- Back button and page title -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" Style="{StaticResource BackButtonStyle}"/>
<TextBlock x:Name="pageTitle" Grid.Column="1" Text="{StaticResource AppName}" IsHitTestVisible="false" Style="{StaticResource PageHeaderTextStyle}"/>
</Grid>
<Grid Grid.Row="2">
<Button Content="Go Details" Command="{Binding DetailsCommand}" />
</Grid>
<VisualStateManager.VisualStateGroups>
<!-- Visual states reflect the application's view state -->
<VisualStateGroup x:Name="ApplicationViewStates">
<VisualState x:Name="FullScreenLandscape"/>
<VisualState x:Name="Filled"/>
<!-- The entire page respects the narrower 100-pixel margin convention for portrait -->
<VisualState x:Name="FullScreenPortrait">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PortraitBackButtonStyle}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridView" Storyboard.TargetProperty="Padding">
<DiscreteObjectKeyFrame KeyTime="0" Value="96,136,86,56"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<!--
The back button and title have different styles when snapped, and the list representation is substituted
for the grid displayed in all other view states
-->
<VisualState x:Name="Snapped">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedBackButtonStyle}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="pageTitle" Storyboard.TargetProperty="Style">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedPageHeaderTextStyle}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridView" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</common:LayoutAwarePage>
I can post for the second view but I don't think that's necessary. Again, if I place a button in the view and set the Command binding to DetailsCommand, the second view pops up just fine. Can't get it to work with item selection on the grid.
From looking at your code, it seems you misunderstood the SelectedItem property of the ListView. It will be populated with one of your WorkListItem objects when the selection changes.
The ListView does not have a command property like the Button does, so you need to handle the SelectionChanged event of the ListView and invoke the Command on your Viewmodel manually.
You can do this in code-behind or take a look at one of the EventToCommand helpers to do it directly in xaml.

Categories

Resources