ListView Inside a Grid inside a ScrollViewer - c#

I have a ListView inside a Grid which in turn is inside an "overall ScrollViewer".
Users should be able to scroll across the entire page horizontally and then scroll vertically down several child list like elements. While I am able to scroll horizontally, placing the outer ScrollViewer around the page content breaks my ListViews
Here is a cut down version of my XAML setup:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="140" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock x:Uid="Title" Text="Title"/>
<ScrollViewer Grid.Row="1" ZoomMode="Disabled"
VerticalScrollBarVisibility="Hidden"
HorizontalScrollBarVisibility="Auto"
VerticalScrollMode="Disabled"
HorizontalScrollMode="Enabled">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="380" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!--My List-->
<ListView x:Name="MyList" Grid.Column="0" />
<Grid x:Name="AppointmentDetailView" Grid.Column="1">
<!--Some other stuff-->
</Grid>
</Grid>
</ScrollViewer>
</Grid>
If I set a fixed height on any parent of the ListView or the ListView itself the scrolling works as expected but fixing the height is undesirable for screens of varying sizes. I tried binding to the ActualHeight of the ListViews parents but no luck.
It seems like the ScrollViewers children are not constrained to the height available even when the ScrollViewer.VerticalScrollMode is disabled. Seems rather odd to me, I would have expected the ScrollViewer's layout logic to be similar to Grid in the direction it has been disabled.
Any help with this is appreciated, Thank you!

I found a workaround that involves wrapping my ScrollViewer in a Grid and binding to the outer Grids ActualHeightProperty on the child element of the ScrollViewer. its a bit of a hack but does what I need it to and goes something like this
<Grid x:Name="ScrollViewerContainer" ...>
<ScrollViewer VerticalScrollMode="Disabled" ...>
<!--Page Content-->
<Grid Height="{Binding ActualHeight, ElementName=ScrollViewerContainer}" ...>
....
Personally I feel like the ScrollViewer should not allow its children to determine its Width/Height when the scroll mode is disabled in a particular direction as it breaks nested ScrollViewer's. It should revert back to the available space. But hey, I'm not Microsoft..

Related

Resizable WPF listbox inside Stack Panel?

I'm trying to create a listBox inside a WPF control which (1) has a minimum height of 80 and (2) which the user can resize to larger vertical height, if desired to see more of the list items. I also want the control, when nested inside a vertical stackPanel, to expand in height as the user expands the list. I've been playing around with gridSplitter. My XAML is below:
<UserControl x:Class="MyControl.FieldControl_SelectFrom"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyControl"
mc:Ignorable="d"
d:DesignWidth="342">
<Grid Background="{x:Static SystemColors.ControlBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" x:Name="textBlock_fieldName" HorizontalAlignment="Left" Margin="20,4,0,0" TextWrapping="Wrap" Text="FieldName" VerticalAlignment="Top" FontWeight="Bold"/>
<ListBox Grid.Row="1" x:Name="selectorBox" MinHeight="80" Height="auto" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Padding="0,0,0,0" Margin="20,4,38,4" VerticalContentAlignment="Center" />
<GridSplitter Grid.Row="2" Height="2" VerticalAlignment="Center"></GridSplitter>
<TextBlock Grid.Row="3" x:Name="textBlock_fieldInfo" HorizontalAlignment="Left" Margin="20,0,0,6" TextWrapping="Wrap" VerticalAlignment="Bottom" FontStyle="Italic" Foreground="Gray">Field Info</TextBlock>
</Grid>
</UserControl>
When I run the project, the listbox is expanded to show the entire contents - with no ability to resize.
What am I missing?
The default resize direction of the GridSplitter is GridResizeDirection.Auto. If you look at the documentation for GridResizeDirection.Auto about the rules that govern behavior of Auto, you'll notice that in your case the GridSplitter -- based on the defined rules as explained in the documentation -- is actually attempting to resize between columns, not rows as you want it to be.
You can make the GridSplitter work in row mode in basically two ways. One is to set the ResizeDirection of the GridSplitter explicitly to GridResizeDirection.Rows. This, however, would not fully solve the problem with the code given in your question.
Because, without specifying the width of the splitter or letting it stretch horizontally (neither of which you have done), the splitter remains a point-like or short vertical line-like element with a width of zero that's practically impossible to hit. So, basically you could tell the splitter to stretch horizontally, which will let the default Auto resize direction operate in Rows mode (and therefore does not require to set the ResizeDirection property explicitly) as well as give the splitter a size that can actually be hit/grabbed with the mouse pointer.

Override MediaElement on top of Webview2

I created a WPF project in which I need display two StackPanels like this:
This screen is child of main Grid
StackPanel 1 will be displayed without any alternation of width and height and I need to display the entire second StackPanel on top of previous StackPanel. Using Canvas and DockPanel doesn't help me in this case.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel VerticalAlignment="Center" Grid.Row="0" x:Name="web1">
<wv2:WebView2 Name="MyWebView"
Height="800" >
</wv2:WebView2>
</StackPanel>
<StackPanel Grid.Row="0" x:Name="videoPlayerPanel">
<Canvas >
<local:VideoPlayer x:Name="videoPlayer" Background="AntiqueWhite"/>
</Canvas>
</StackPanel>
</Grid>
I agree with #thatguy answer , if we use the zIndex we can overlap the element in WPF, But the question here is related to webview2 and mediaElement.
As of now webview2 not allow another element to come on top.
So there is no way to display your mediaElement on top of webview as of now.
Reffer to this Link for this issue : Webview2 issue
You can try to display mediaElement using popup but this will give other problems
I think this is the only answer to your question right now .
The order in which you define the StackPanels inside the Grid matters. The next item is displayed above the previous one. In your example, videoPlayerPanel will be above web1, because it is defined after web1. There are two options to alter this behavior.
Change the order, define videoPlayerPanel before web1, to display web1 above videoPlayerPanel.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" x:Name="videoPlayerPanel">
<Canvas >
<local:VideoPlayer x:Name="videoPlayer" Background="AntiqueWhite"/>
</Canvas>
</StackPanel>
<StackPanel VerticalAlignment="Center" Grid.Row="0" x:Name="web1">
<wv2:WebView2 Name="MyWebView"
Height="800" >
</wv2:WebView2>
</StackPanel>
</Grid>
Define the Z-Order explicitly by setting a ZIndex for the items.
Gets or sets a value that represents the order on the z-plane in which an element appears. [...] The greater the value of a given element, the more likely the element is to appear in the foreground.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel VerticalAlignment="Center" Grid.Row="0" x:Name="web1" ZIndex="1">
<wv2:WebView2 Name="MyWebView"
Height="800" >
</wv2:WebView2>
</StackPanel>
<StackPanel Grid.Row="0" x:Name="videoPlayerPanel">
<Canvas >
<local:VideoPlayer x:Name="videoPlayer" Background="AntiqueWhite"/>
</Canvas>
</StackPanel>
</Grid>
The default ZIndex is zero, and that explains why the order in the Grid matters.
Members of a Children collection that have equal ZIndex values are rendered in the order in which they appear in the visual tree. You can determine the index position of a child by iterating the members of the Children collection.

WPF Stackpanel height not resizing when removing a usercontrol

I have a stackpanel in a grid row with the row height set to auto.
I add user controls at runtime and the height resizes fine, when removing the user controls the height does not reduce though. I have tried to clear the stackpanel children, remove them one by one and also implemented IDisposable in each user control but when the child count shows zero the height has not reduced.
Sample XAML below, any help would be welcomed please?
<Grid x:Name="TestGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Test Header" Style="{StaticResource SubHeaderTextBlock}" />
</StackPanel>
<StackPanel x:Name="ChildItems" Grid.Row="1" />
</Grid>
Replace the StackPanel with a Grid. Grids stretch and retract better than StackPanels.
Instated of removing put Visibility to Collapsed

Route event to element under the current element

I've been trying to have one canvas with two layers. One layer scrolls horizontally, the second one is on top and scrolls vertically.
In the second layer (the one that scrolls vertically), I stacked a transparent grid (or panel) and a panel with information so that we can see the first layer that is under this one and if we scroll up, we have the information that appears on the screen.
That works like a charm except that if I scroll horizontally, the first layer (the one under) does not scroll at all. It's not a problem if the vertical scrolls does not scroll if we swipe the transparent grid.
This is my xaml
<Canvas x:Name="Canvas">
<local:MyPage x:Name="PageContainer"/> <!--This one scrolls horizontally -->
<ScrollViewer
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Hidden"
Height="{Binding ActualHeight, ElementName=UcRoot}">
<!--This one scrolls vertically and appears on top -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Height="600" Width="600" Grid.Row="0" x:Name="TransparentGrid" ></Grid>
<Grid x:Name="Information" Background="Azure" Height="1200" Width="600" Grid.Row="1">
</Grid>
</Grid>
</ScrollViewer>
</Canvas>
I tried many things on the transparent grid (setting width to 1, removing it and setting the information grid margin top to 1200 for example) but the grid captures the event and does not relay to my page.
Can I get some help?
Thanks!
You have to set the background to 'Transparent' to the grid in order to be able to tap on it and swipe.. and you maybe need these properties to play with:
ScrollViewer.VerticalScrollMode
ScrollViewer.HorizontalScrollMode
Although, this is my suggested solutions:
<ScrollViewer ScrollViewer.VerticalScrollMode="Enabled" ScrollViewer.HorizontalScrollMode="Disabled" >
<Grid >
<TextBlock Text="contnet" />
</Grid>
</ScrollViewer>
<ScrollViewer ScrollViewer.VerticalScrollMode="Disabled" ScrollViewer.HorizontalScrollMode="Enabled" >
<Grid Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Height="600" Width="600" Grid.Row="0" x:Name="TransparentGrid" Background="Transparent" ></Grid>
<Grid x:Name="Information" Background="Azure" Height="1200" Width="600" Grid.Row="1"/>
</Grid>
</ScrollViewer>
</Canvas>

How to make a certain section scrollable

I have got the following XAML:
<StackPanel HorizontalAlignment="Center">
<Image Name="logo" Source="logo.png" Margin="0,0,0,50"/>
<ScrollViewer>
<Dashboard_Control:AlignableWrapPanel x:Name="wrapPanel"/>
</ScrollViewer>
<TextBlock FontWeight="Bold" HorizontalAlignment="Center" x:Name="txtBottomText"></TextBlock>
</StackPanel>
I would like that the wrapPanel is scrollable only, so that the txtBottomText control will always be at the bottom as you scroll, and the logo image control will always be at the top - essentially only allowing the wrapPanel to be scrollable.
I have tried adding a ScrollViewer as shown above, however it never shows. I even tried adding a property to always have the vertical scrollbar, however it appears without letting me scroll (the scrollbar is disabled).
I suspect that this is because my wrapPanel's content is dynamically generated at run-time like so:
wrapPanel.Children.Add(content);
Any ideas what I can do to fix this?
It's not because of your wrapPanel's content. but because you're using a StackPanel to contain everything.
StackPanels grow indefinitely in the direction determined by their Orientation property. By default, that's vertically.
In your case, that makes the ScrollViewer "think" it has enough available space to stretch itself to accomodate its content, instead of activating the scroll bars. So it simply gets bigger as the WrapPanel inside gets bigger, pushing the TextBlock down.
To avoid this, you need to use a different Panel that is able to properly assign the available space to each control. Like a Grid.
<Grid HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image Name="logo" Source="logo.png" Margin="0,0,0,50"/>
<ScrollViewer Grid.Row="1">
<Dashboard_Control:AlignableWrapPanel x:Name="wrapPanel"/>
</ScrollViewer>
<TextBlock Grid.Row="2" FontWeight="Bold" HorizontalAlignment="Center" x:Name="txtBottomText"></TextBlock>
</Grid>
I usually say that StackPanels tend to be overused :P They're practical and easy to use, but they have a bunch of quirks and limitations that make them not suitable for many situations, like this one.
EDIT: Make sure, also, that the Grid is not contained inside another vertical StackPanel, a Grid row with Height set to Auto, or something like that.
If the Height of your WrapPanel exceeds the height of the control or window where you have put the controls, the Textblock below the Wrap Panel inside the Stack Panel is put after the Wrap panel and so it is below the scroll area.
To be able to leave the Textblock always visible you have two means:
1) limit the height of your Wrap panel
2) Use a container like a Grid with 3 rows instead of the stack panel and put the Row Heights of the Grid respectively to
Auto, *, Auto so that the image on top and the textblock on bottom use the space of their content and the Scroll panel uses all the space remaining
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Image Grid.Row ="0" Source="myimage.jpg" />
<ScrollViewer Grid.Row="1">
<WrapPanel Height="1200" Width="600">
<TextBlock>Ciao sono io</TextBlock>
</WrapPanel>
</ScrollViewer>
<TextBox Grid.Row="2" TextWrapping="Wrap" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Text="IO c'ero" />
</Grid>
You have to set a fixed heigh to your scrollviewer - if not, the scrollviewer takes as much space as he needs, in order to show the complete content of its children.
Solutions:
Set the Height property of your scollviewer
Use a grid instead of a stackpanel an set the first and third rowheight to auto

Categories

Resources