As discussed already here I've a problem with showing content in a GridView. Based on this article I found out that GridView set the Height property for the items to the height of the first item. The problem for me is that I'd like to have the Height adjusted apdaptive based on the height of the content.
So if the second item in a row is the biggest, all items in this row should get the size of the second item.
I've used this code for showing the GridView:
<GridView ItemsSource="{Binding}" ScrollViewer.VerticalScrollBarVisibility="Disabled" Width="1080">
<GridView.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding ListData, Converter={StaticResource DataBindingDebugConverter}}" x:Name="BirthdayListView" HorizontalAlignment="Center" Margin="0,20,0,0">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="🎂"
FontSize="16"
Grid.Column="0"
Margin="0,0,10,10"
FontFamily="Sergoe UI"
Style="{StaticResource BasicTextBlock}"/>
<TextBlock Text="{Binding NameString, Converter={StaticResource DataBindingDebugConverter}}"
Grid.Column="2"
Margin="10,0,0,0"
FontSize="16"
Style="{StaticResource BasicTextBlock}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemContainerStyle>
<Style TargetType="ContentControl">
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0,20,0,0"/>
<Setter Property="Width" Value="360" />
<Setter Property="VerticalContentAlignment" Value="Top" />
</Style>
</GridView.ItemContainerStyle>
</GridView>
EDIT:
If the calendar entries are on the first entry (Sonntag) everything is fine.
If the calendar entries are on the second item (Montag) they are hidden and the ItemHeight is not increasing.
Based on this article I found out that GridView set the Height property for the items to the height of the first item.
As you known the row height of GridView depend on the first item not the highest item. So we may need to custom a panel for the GridView's ItemPanel. For example, since the Width of your GridView is fixed value, we can create a CustomPanel as follows:
public class CustomPanel : Panel
{
private double _maxWidth;
private double _maxHeight;
protected override Size ArrangeOverride(Size finalSize)
{
var x = 0.0;
var y = 0.0;
foreach (var child in Children)
{
if ((_maxWidth + x) > finalSize.Width)
{
x = 0;
y += _maxHeight;
}
var newpos = new Rect(x, y, _maxWidth, _maxHeight);
child.Arrange(newpos);
x += _maxWidth;
}
return finalSize;
}
protected override Size MeasureOverride(Size availableSize)
{
foreach (var child in Children)
{
child.Measure(availableSize);
var desirtedwidth = child.DesiredSize.Width;
if (desirtedwidth > _maxWidth)
_maxWidth = desirtedwidth;
var desiredheight = child.DesiredSize.Height;
if (desiredheight > _maxHeight)
_maxHeight = desiredheight;
}
var itemperrow = Math.Floor(availableSize.Width / _maxWidth);
var rows = Math.Ceiling(Children.Count / itemperrow);
return new Size(itemperrow * _maxWidth,_maxHeight * rows );
}
}
Then replace the ItemsPanelTemplate of GridView with the CustomPanelin XAML as follows:
<GridView ItemsSource="{Binding}" Width="1080" >
<GridView.ItemTemplate>
...
</GridView.ItemTemplate>
<GridView.ItemContainerStyle>
...
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<local:CustomPanel />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
Related
I have two Canvas panels in ScrollViewer. One is the main canvas which is having a grid shape drawn on its back ground. Then I have two ItemsControl. The first ItemsControl is having Stackpanel as its ItemsPanel with Horizontal Orientation. The second ItemsControl is having Canvas as its Panel. On this canvas I am drawing Line objects in DataTemplate of Itemscontrol.There is PreviewMouseWheel event on this canvas. In the event handler I am zooming this canvas which is zooming the Line objects. The width of this canvas is binded to ViewModel property CanvasWidth. Also this will change the width of Outer Canvas as its width is also binded to ViewModel Property CanvasWidth. When the PreviewMouseWheel is fired, I am adding more grid lines on main Canvas. I have TextBlock over them as DataTemplate of ItemsSource. Before zooing, the content of last TextBlock was 14260. After zoomin it should remain 14260. but the step value of two consecutive TextBlock should be reduced. Right now I am not able to see the whole content through ScrollViewer. The step size is reduced which was desired but the new grid lines which are drawn cannot be seen throught Scrollviewer. i know there is content. but I am unable to acces it. The scrollviewer is not showing it.
<Grid x:Name="grid1" >
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<ScrollViewer Name="scrollViewer" HorizontalScrollBarVisibility="Auto" Grid.Row="1" Grid.Column="3" Margin="10,10,0,10" >
<Canvas Name="back_canvas" Height="12000" Width="{Binding CanvasWidth}" Margin="0,0,10,0" >
<Canvas.Background>
<DrawingBrush TileMode="Tile" Viewport="0,0,40,40" ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,50,50"/>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen Brush="Gray" Thickness="1"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Canvas.Background>
<ItemsControl ItemsSource="{Binding TimeAxis}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Margin="0,0,3,0" Width="37" Background="GreenYellow" >
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl ItemsSource="{Binding Lines}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Height="12000" Background="Transparent" Name="front_canvas"
PreviewMouseWheel="OnPreviewMouseWheel"
Width="{Binding CanvasWidth, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
</Line>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
</ScrollViewer>
</Grid>
private void UpdateGraph(Canvas canvas, double deltaValue)
{
List<MarkerView> markers = new List<MarkerView>();
scaleFactor += deltaValue;
double tempScale = scaleFactor;
if (scaleFactor < 1.0)
{
scaleFactor = 1.0;
}
if (scaleFactor > maximumScale)
{
scaleFactor = maximumScale;
}
if (tempScale > 0)
{
totalSamples = graphVM.maxSignalLength;
maximumCanvasWidth = totalSamples * maximumDeltaDistance;
if(scaleFactor<=maximumDeltaDistance)
{
ScaleTransform scaleTransform = new ScaleTransform(scaleFactor, 1);
canvas.RenderTransform = scaleTransform;
verticalLines.ForEach(x =>
{
x.RenderTransformOrigin = new Point(1, 1);
x.RenderTransform = new ScaleTransform(1 / scaleTransform.ScaleX, 1 / scaleTransform.ScaleY);
});
if (deltaValue < 0)
{
graphVM.CanvasWidth = graphVM.InitialCanvasWidth * tempScale;
}
else
{
if (graphVM.InitialCanvasWidth * scaleFactor > maximumCanvasWidth)
graphVM.CanvasWidth = maximumCanvasWidth;
else
graphVM.CanvasWidth = graphVM.InitialCanvasWidth * scaleFactor;
}
graphVM.ResetLabels();
DeltaDistance = canvas.Width / totalSamples;
MarkerView markerRed =
UIHelperView.FindChild<MarkerView>(Application.Current.MainWindow, "splitterRed");
MarkerView markerGreen =
UIHelperView.FindChild<MarkerView>(Application.Current.MainWindow, "splitterGreen");
markers.Add(markerRed);
markers.Add(markerGreen);
// Move Markers with zooming
foreach (MarkerView marker in markers)
{
marker.Delta = DeltaDistance; // after zooming if you move the marker then this value will be used to get correct position
Canvas.SetLeft(marker, marker.XPosition * DeltaDistance);
}
markers.Clear();
}
}
}
here is the output picture https://imgur.com/a/7WTrBoc
this is zoomed output https://imgur.com/C7SCOSJ
RenderTransform doesn't affect ActualWidth/Height of the control. Try using LayoutTransform instead.
I am currently trying to find/implement a WPF control, which is a combination of a Grid and a StackPanel. That means, I like to have two columns with several items. An item is another control (e.g. single Label, TextBox with label in a panel, ...).
If an item is collapsed, the empty space should be filled with the next item, means I have always as less space used in the control as possible (without gaps between the single items).
I attached two images how it should look like.
Initial:
Item4 is collapsed (notice the shift of following up items):
Does anybody have an idea or experience how to do something like that?
you can use a ListView that uses a StackPanel or a DockPanel as ItemTemplate.
This is an example (simplified) of what I use to display an observable collection of objects in a list with Grid and DockPannel:
<ListView x:Name="lbxDroppedDatas" SelectionMode="Single" AllowDrop="True" BorderThickness="0" Padding="0" Margin="0" ScrollViewer.HorizontalScrollBarVisibility="Disabled" SelectionChanged="lbxDroppedDatas_SelectionChanged" PreviewKeyDown="lbxDroppedDatas_PreviewKeyDown" PreviewMouseRightButtonDown="lbxDroppedDatas_PreviewMouseRightButtonDown" >
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel Grid.Row="0" Width="{Binding Path=ActualWidth, ElementName=Container}" Height="40" Margin="1" LastChildFill="True">
<CheckBox DockPanel.Dock="Left" IsChecked="{Binding IsChecked}" VerticalAlignment="Center" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" />
<Label Content="{Binding Name}" Foreground="{Binding LineBrush}" FontWeight="Bold" FontSize="12" Margin="5" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="0" MouseEnter="Label_MouseEnter" MouseLeave="Label_MouseLeave"/>
<TextBox DockPanel.Dock="Right" Width="60" MaxLength="14" Text="{Binding CurrentValue, StringFormat=N}" Margin="0,0,33,0" Background="Transparent" Foreground="{Binding LineBrush}" BorderBrush="{Binding LineBrush}" BorderThickness="1" VerticalAlignment="Center" HorizontalAlignment="Right" IsEnabled="False"/>
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" VerticalAlignment="Stretch" Margin="0"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
You could bind the visibility of your list element to a collapsed or visible property.
I'd solve this problem in the following way:
start with creating a grid with two stack panels (the grid resides within a UserControl or any other placeholder):
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel x:Name="LeftPanel" x:FieldModifier="private" Orientation="Vertical" />
<StackPanel x:Name="RightPanel" x:FieldModifier="private" Grid.Column="1" Orientation="Vertical" />
</Grid>
to control your items, create a list of items, preferably within the code of your UserControl:
private List<FrameworkElement> m_items = new List<FrameworkElement>();
for the items you don't want to be visible set the Visibility to Hidden or Collapsed.
you'd need some method that will select the visible items and place them alternating to the left and right panel. I've came up with some quick method that you need to call each time your list changes (an item is added or removed, visibility of an item is changed):
public void SortItems()
{
this.LeftPanel.Children.RemoveRange(0, this.LeftPanel.Children.Count);
this.RightPanel.Children.RemoveRange(0, this.RightPanel.Children.Count);
this.m_items.Where(i => i.Visibility == Visibility.Visible).ToList().ForEach((i) => { (this.LeftPanel.Children.Count == this.RightPanel.Children.Count ? this.LeftPanel : this.RightPanel).Children.Add(i); } );
}
The method simply removes all children of the stack panels and then traverses through the items' list choosing only those which are Visible and adds one to the left panel if both panels have the same amount of items in them and to the right panel otherwise.
If you need some other way of selecting into which panel the following item should be added (e.g. ActualHeight) simply change the condition that is selecting the panels.
If you want to make this method more elegant you can add some events or dependency properties that will call SortItems automatically. Anyway, it's a good start.
Thank you very much for all the different solutions. Finally I solved it with the suggestion from Sinatr. So I created my own panel and override the ArrangeOverride:
protected override Size ArrangeOverride(Size finalSize)
{
List<UIElement> visibleItems = new List<UIElement>();
double xColumn1 = 0;
double xColumn2 = (finalSize.Width / 2) + (WIDTH_COLUMN_SEPERATOR / 2);
double y = 0;
double columnWidth = (finalSize.Width - WIDTH_COLUMN_SEPERATOR) / 2;
for (int i = 0; i < InternalChildren.Count; i++)
{
UIElement child = InternalChildren[i];
if (child.Visibility != Visibility.Collapsed)
{
visibleItems.Add(child);
}
}
for (int i = 0; i < visibleItems.Count; i++)
{
if (i >= (visibleItems.Count - 1))
{
visibleItems[i].Arrange(new Rect(xColumn1, y, columnWidth, visibleItems[i].DesiredSize.Height));
}
else
{
UIElement leftItem = visibleItems[i];
UIElement rightItem = visibleItems[i + 1];
double rowHeight = leftItem.DesiredSize.Height > rightItem.DesiredSize.Height ? leftItem.DesiredSize.Height : rightItem.DesiredSize.Height;
leftItem.Arrange(new Rect(xColumn1, y, columnWidth, rowHeight));
rightItem.Arrange(new Rect(xColumn2, y, columnWidth, rowHeight));
y += rowHeight;
i++;
}
}
return finalSize;
}
I also created my own UserControl for the Items:
<Grid DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label x:Name="captionLabel" Grid.Row="0" Content="{Binding Caption}"/>
<ContentPresenter x:Name="inputMask" Grid.Row="1" Content="{Binding InputMask, ElementName=userControlBRAIN2AttributePanelItem}" />
</Grid>
So I get te following result (from my test application):
enter image description here
with collapsed item 3:
enter image description here
I'm surprised that no one sugested the use of an UniformGrid.
All you have to do is declar an UniformGrid, set Columns to 2 and add your items. Items that are collapsed should have its Visibility set to Collapsed (duh).
Here's an example:
<UniformGrid Columns="2"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<TextBlock Text="Item 1 " />
<TextBlock Text="Item 2 " />
<TextBlock Text="Item 3 " />
<TextBlock Text="Item 4 " />
</UniformGrid>
Will produce the following result:
And when the Visibility of the second TextBlock is set to Collapsed, here's what it looks like:
I have a GridView as my zoomed out view in a SemanticZoom control. This GridView uses a custom DataTemplateSelector as the ItemTemplateSelector. The DataTemplateSelector returns a DataTemplate with different Foreground color, depending upon whether or not the Group has any items in it.
However, even though the DataTemplateSelector seems to work and returns the correct template, only one template is ever used by the GridView and the text is all the same color.
Here is the XAML of the GroupedListView:
<UserControl
x:Class="GroupList.GroupList.GroupedListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:GroupList.GroupList"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:data="using:GroupList.Model"
xmlns:wuxdata="using:Windows.UI.Xaml.Data"
mc:Ignorable="d">
<UserControl.Resources>
<!-- Use a collection view source for content that presents itself as a list of items that can be grouped or sorted. Otherwise, you can use x:Bind
directly on the ListView's item source to for further optimization. Please see the AppUIBasics sample for an example of how to do this. -->
<CollectionViewSource x:Name="ContactsCVS" IsSourceGrouped="True" />
<Style TargetType="TextBlock" x:Key="TileHeaderTextStyle" BasedOn="{StaticResource ProximaNovaSemiBold}">
<Setter Property="FontSize" Value="54" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontWeight" Value="ExtraBold"/>
<Setter Property="FontStretch" Value="Expanded" />
</Style>
<Style TargetType="TextBlock" x:Key="TileHeaderTextStyleGray" BasedOn="{StaticResource TileHeaderTextStyle}">
<Setter Property="Foreground" Value="Khaki" />
</Style>
<!-- When using x:Bind, you need to set x:DataType -->
<DataTemplate x:Name="ContactListViewTemplate" x:DataType="data:Contact">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Ellipse x:Name="Ellipse"
Grid.RowSpan="2"
Width ="32"
Height="32"
Margin="6"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Fill="LightGray"/>
<TextBlock Grid.Column="1"
Text="{x:Bind Name}"
x:Phase="1"
Style="{ThemeResource BaseTextBlockStyle}"
Margin="12,6,0,0"/>
<TextBlock Grid.Column="1"
Grid.Row="1"
Text="{x:Bind Position}"
x:Phase="2"
Style="{ThemeResource BodyTextBlockStyle}"
Margin="12,0,0,6"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="GrayZoomedOutTemplate" x:DataType="wuxdata:ICollectionViewGroup">
<TextBlock Text="{x:Bind Group.(data:GroupInfoList.Key)}" Margin="0,0,0,5" Style="{StaticResource TileHeaderTextStyleGray}" />
</DataTemplate>
<DataTemplate x:Key="ZoomedOutTemplate" x:DataType="wuxdata:ICollectionViewGroup">
<TextBlock Text="{x:Bind Group.(data:GroupInfoList.Key)}" Margin="0,0,0,5" Style="{StaticResource TileHeaderTextStyle}" />
</DataTemplate>
<local:GroupEmptyOrFullSelector x:Key="GroupEmptyOrFullSelector" Empty="{StaticResource GrayZoomedOutTemplate}" Full="{StaticResource ZoomedOutTemplate}" />
</UserControl.Resources>
<!--#region Navigation Panel -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical">
<TextBlock Margin="15,0,0,0" Text="Paula's SemanticZoom Sandbox" Grid.Row="0"
VerticalAlignment="Center"
Style="{ThemeResource TitleTextBlockStyle}" />
<Button x:Name="ZoomInOutBtn" Content="ABC↕" Click="ZoomInOutBtn_Click" Width="60" HorizontalAlignment="Center" BorderThickness="0" />
</StackPanel>
<!--#endregion-->
<SemanticZoom x:Name="ZoomControl" Grid.Row="1">
<SemanticZoom.ZoomedInView>
<GridView ItemsSource="{x:Bind ContactsCVS.View}"
ItemTemplate="{StaticResource ContactListViewTemplate}"
SelectionMode="Single"
ShowsScrollingPlaceholders="True">
<GridView.GroupStyle>
<GroupStyle HidesIfEmpty="True">
<GroupStyle.HeaderTemplate>
<DataTemplate x:DataType="data:GroupInfoList">
<TextBlock Text="{x:Bind Key}"
Style="{ThemeResource TitleTextBlockStyle}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
</SemanticZoom.ZoomedInView>
<SemanticZoom.ZoomedOutView>
<GridView ItemTemplateSelector="{StaticResource GroupEmptyOrFullSelector}" ScrollViewer.VerticalScrollBarVisibility="Disabled" Margin="0, 200" Width="475" ItemsSource="{x:Bind ContactsCVS.View.CollectionGroups}" SelectionMode="None" >
</GridView>
</SemanticZoom.ZoomedOutView>
</SemanticZoom>
</Grid>
</UserControl>
And here is the DataTemplateSelector:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.Foundation.Collections;
using GroupList.Model;
namespace GroupList.GroupList
{
/// <summary>
/// This determines whether or not the Group passed during binding is empty or not and allows selection
/// of the proper DataTemplate based on this value.
/// </summary>
class GroupEmptyOrFullSelector : DataTemplateSelector
{
private DataTemplate _full;
private DataTemplate _empty;
public DataTemplate Full
{
set { _full = value; }
get { return _full; }
}
public DataTemplate Empty
{
set { _empty = value; }
get { return _empty; }
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
var itemType = item.GetType();
var isGroup = itemType.Name == "GroupInfoList";
bool isEmpty = false;
GroupInfoList groupItem;
if (isGroup)
{
groupItem = item as GroupInfoList;
isEmpty = groupItem.Count == 0;
}
// Disable empty items
var selectorItem = container as SelectorItem;
if (selectorItem != null)
{
selectorItem.IsEnabled = !isEmpty;
}
if (isEmpty)
{
return Empty;
}
else
{
return Full;
}
}
}
}
So, here was the problem:
In the DataTemplateSelector listing, even if a passed "object item" was not a group, it fell through to the template selection logic. Sometimes, the "object" passed to your function is not a Group object, but rather a generic DependencyObject. In such a case, your template selection logic needs to return a default template, returning one of the specific templates only if the "object item" is a Group object. Thus, the new function looks like this:
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
var itemType = item.GetType();
var isGroup = itemType.Name == "GroupInfoList";
bool isEmpty = false;
GroupInfoList groupItem;
if (isGroup)
{
groupItem = item as GroupInfoList;
isEmpty = groupItem.Count == 0;
// Disable empty items
var selectorItem = container as SelectorItem;
if (selectorItem != null)
{
selectorItem.IsEnabled = !isEmpty;
}
if (isEmpty)
{
return Empty;
}
else
{
return Full;
}
}
return Full;
}
is there any control that can auto resize items inside. I need to contain textblocks inside ItemsControl only in one row, so if total items width larger then container.Width, it will change each item's width. UWP
<ItemsControl Grid.Column="1"
ItemsSource="{Binding Path=NavigationHistory, ElementName=Main, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
x:Name="BroadComb"
MaxHeight="24"
Margin="10,0,0,0" VerticalAlignment="Center" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<HyperlinkButton Command="{Binding Path=NavigateCommand, ElementName=Main}" CommandParameter="{Binding}" Margin="10,0,0,0" Foreground="{ThemeResource AppAccentForegroundLowBrush}" >
<HyperlinkButton.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center"
TextTrimming="None"
Text="{Binding Path=DisplayName}"
FontSize="10"
FontWeight="Bold"
Foreground="{ThemeResource AppAccentForegroundLowBrush}">
<i:Interaction.Behaviors>
<core:DataTriggerBehavior Binding="{Binding Path=CanBeTrim}" Value="True">
<core:ChangePropertyAction PropertyName="TextTrimming" Value="WordEllipsis"/>
</core:DataTriggerBehavior>
<core:DataTriggerBehavior Binding="{Binding Path=CanBeTrim}" Value="False">
<core:ChangePropertyAction PropertyName="TextTrimming" Value="None"/>
</core:DataTriggerBehavior>
</i:Interaction.Behaviors>
</TextBlock>
<FontIcon Margin="10,0,0,0" HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="ms-appx:/Assets/Fonts/MyBook-Regular.ttf#MyBook"
FontSize="10"
Glyph="2" Foreground="{ThemeResource AppAccentForegroundLowBrush}" />
</StackPanel>
</DataTemplate>
</HyperlinkButton.ContentTemplate>
</HyperlinkButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
One possibility is to use a Grid with your desired controls in it's columns set to HorizontalAlignment="Stretch":
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="abc" HorizontalAlignment="Stretch" />
<TextBlock Grid.Column="1" Text="xyz" HorizontalAlignment="Stretch" />
</Grid>
This will stretch both controls over the maximum available width according to the Grid's container and make them smaller or bigger if the available space changes.
Most of the time, you will only want to set one column to fill the available space (Width="*") and set the other columns to a fixed or relative width. You can experiment with those settings.
Else we would need a more exact specification of what you want to achieve.
is there any control that can auto resize items inside. I need to contain textblocks inside ItemsControl only in one row, so if total items width larger then container.Width, it will change each item's width. UWP
What you need is to change the default ItemsPanel of GridView. You can create your own Custom Panel to let the texts be arranged in only one row:
Create your own custom Panel OneRowPanel.cs:
public class OneRowPanel:Panel
{
double itemHeight=0;
protected override Size MeasureOverride(Size availableSize)
{
int count = Children.Count;
foreach (FrameworkElement child in Children)
{
child.Measure(new Size(availableSize.Width/count,availableSize.Height));
if (child.DesiredSize.Height > itemHeight)
{
itemHeight = child.DesiredSize.Height;
};
}
// return the size available to the whole panel
return new Size(availableSize.Width, itemHeight);
}
protected override Size ArrangeOverride(Size finalSize)
{
// Get the collection of children
UIElementCollection mychildren = Children;
// Get total number of children
int count = mychildren.Count;
// Arrange children
int i;
for (i = 0; i < count; i++)
{
//get the item Origin Point
Point cellOrigin = new Point(finalSize.Width / count * i,0);
// Arrange child
// Get desired height and width. This will not be larger than 100x100 as set in MeasureOverride.
double dw = mychildren[i].DesiredSize.Width;
double dh = mychildren[i].DesiredSize.Height;
mychildren[i].Arrange(new Rect(cellOrigin.X, cellOrigin.Y, dw, dh));
}
// Return final size of the panel
return new Size(finalSize.Width, itemHeight);
}
}
Use it in your Xaml and set the TextBlock.TextTrimming to CharacterEllipsis:
<Page
x:Class="AutoResizeItemsSample.MainPage"
...
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="TextTemplate">
<TextBlock Text="{Binding Text}" TextTrimming="CharacterEllipsis">
</TextBlock>
</DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Name="rootPanel">
<GridView Name="gridView" ItemTemplate="{StaticResource TextTemplate}" >
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<local:OneRowPanel ></local:OneRowPanel>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</StackPanel>
</Grid>
</Page>
Here is the Result:
Here is the complete demo:AutoResizeItemsSample.
Solve this easily with ListView. The ItemsPanel is already a StackPanel and the individual item will resize as needed. If you need the horizontal width of each item to be different, that's supported out of the box, too. I think the solution is to simply choose the ListView control.
I'm developing Universal Window App on Windows 10 platform and my page looks like this example :
Main page contain a pivot control with 4 pivot items (PAGE 1, PAGE 2, ...).
PAGE 1 contain a red stackpanel which contain a listview with horizontal scrolling.
My problem is, when i want to scroll my red listview horitontaly, my pivot swipe to next page.
I want to disable pivot swipe during listview scrolling (But only during listview scrolling).
I tried to get scrollviewer from listview and to listen viewChange from scrollviewer to disable pivot swipe but without success.
Everything work but set IsHitTestVisible to false seems to not work.
Here is my code :
ScrollViewer scrollViewer = ListViewHelper.GetScrollViewer(myListView);
scrollViewer.ViewChanged += scrollview_ViewChanged;
private void scrollview_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
var scrollviewer = sender as ScrollViewer;
if (e.IsIntermediate)
{
mainPivot.IsHitTestVisible = false;
} else
{
mainPivot.IsHitTestVisible = true;
}
}
And my ListViewHelper class :
public static class ListViewHelper
{
public static ScrollViewer GetScrollViewer(this DependencyObject element)
{
if (element is ScrollViewer)
{
return (ScrollViewer)element;
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
var child = VisualTreeHelper.GetChild(element, i);
var result = GetScrollViewer(child);
if (result == null)
{
continue;
}
else
{
return result;
}
}
return null;
}
}
And my xaml code :
<Pivot x:Name="mainPivot">
<PivotItem x:Name="pivot1">
<!-- Header -->
<PivotItem.Header>
<controls:TabHeader x:Uid="pivot1HeaderTitle"
Label=""
Glyph=""/>
</PivotItem.Header>
<!-- Content -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="110" />
<RowDefinition Height="30" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel x:Name="localeEditionsFavory"
Grid.Row="0">
[...]
<!-- HERE is my listview -->
<ListView x:Name="localeEditionsFavoryList"
Height="80"
ItemsSource="{Binding FavoritesItems}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollMode="Enabled">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal">
</StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Padding" Value="0,0,0,0" />
<Setter Property="Margin" Value="10" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid x:Name="favoryList">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="55" />
</Grid.RowDefinitions>
<Rectangle x:Name="strokedasharray"
Grid.Column="0"
Grid.Row="0"
Fill="White"
Opacity="0.2"
RadiusX="5"
RadiusY="5"/>
<TextBlock Grid.Column="0"
Grid.Row="0"
Text="{Binding FavoriteItem.EditionKey}"
TextWrapping="WrapWholeWords"
Height="auto"
Foreground="White"
FontSize="14"
Margin="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextTrimming="CharacterEllipsis"
TextAlignment="Center"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
[...]
<ScrollViewer VerticalScrollMode="Auto"
VerticalScrollBarVisibility="Auto"
Grid.Row="3">
<controls:NewsItemControl x:Name="NewsListControl"
Visibility="{Binding Busy, Converter={StaticResource InverseBoolToVisibilityConverter}}"/>
</ScrollViewer>
</Grid>
</PivotItem>
[...]
Does any one has an idea to resolve this problem ?
The undesired behavior you're seeing is a result of scroll chaining. Both the ListView and Pivot contain ScrollViewers in their control templates making this a nested ScrollViewer situation. When you have a ScrollViewer contained within the tree of another and attempt to scroll via touch beyond the extent of the inner ScrollViewer then the outer ScrollViewer engages and begins scrolling.
With chaining disabled you’d only be able to scroll the outer ScrollViewer by beginning the manipulation on a hit-testable area of the outer ScrollViewer. Chaining is enabled by default on the ScrollViewer so when you attempt to scroll past the end of the list the chaining kicks in and is recognized by the Pivot as an attempt to “scroll” to the next pivot item.
Disable chaining on the ListView's ScrollViewer (and remove the ListViewHelper stuff in code behind) by setting the ScrollViewer.IsHorizontalScrollChainingEnabled="False" attached property:
<!-- HERE is my listview -->
<ListView x:Name="localeEditionsFavoryList"
Height="80"
ItemsSource="{Binding FavoritesItems}"
ScrollViewer.IsHorizontalScrollChainingEnabled="False"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollMode="Enabled">
If you need to make the ListView horizontal scrolling, you can achieve this just in XAML code by modifying the style of the ListView like this:
<Style x:Key="ListViewStyle" TargetType="ListView">
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled" />
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Enabled" />
<Setter Property="ScrollViewer.IsHorizontalRailEnabled" Value="True" />
<Setter Property="ScrollViewer.VerticalScrollMode" Value="Disabled" />
<Setter Property="ScrollViewer.IsVerticalRailEnabled" Value="False" />
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
Now if you disable the scrolling of Pivot when you scroll the ListView of "PAGE 1", you can edit your code like this:
public void Page_Loaded(object sender, RoutedEventArgs e)
{
var scrollViewer = FindChildOfType<ScrollViewer>(mainPivot);
scrollViewer.HorizontalScrollMode = ScrollMode.Disabled;
}
private void PivotSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (mainPivot.SelectedIndex == 0)
{
var scrollViewer = FindChildOfType<ScrollViewer>(mainPivot);
scrollViewer.HorizontalScrollMode = ScrollMode.Disabled;
}
}
public static T FindChildOfType<T>(DependencyObject root) where T : class
{
var queue = new Queue<DependencyObject>();
queue.Enqueue(root);
while (queue.Count > 0)
{
DependencyObject current = queue.Dequeue();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(current); i++)
{
var child = VisualTreeHelper.GetChild(current, i);
var typedChild = child as T;
if (typedChild != null)
{
return typedChild;
}
queue.Enqueue(child);
}
}
return null;
}