I am trying to do an interface in WPF where a list of item is displayed, taking as little vertical space as possible:
My instinct was to use an ItemsControl to bind my list, and to put the UI for each item into a WrapPanel. Unfortunately by default, each item starts at a new line regardless of the window's size. Adding a StackPanel with Orientation="Horizontal" makes all items in a single line, regardless of the size...
<!--<ScrollViewer Grid.Row="0" Grid.Column="0"
VerticalScrollBarVisibility="Auto">-->
<ItemsControl Margin="0,4" ItemsSource="{Binding Path=Watchers}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type Core:Watcher}">
<WrapPanel Orientation="Horizontal">
<TextBlock Margin="0,2" Text="{Binding Path=Name}"
Width="250px" />
<TextBox Text="{Binding Path=Value, Mode=OneWay}"
Width="300px">
</TextBox>
</WrapPanel>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
<!--</ScrollViewer>-->
Any pointers?
Bonus point: Where should I add a ScrollViewer in order to have the behavior shown in my mockup?
Thanks a lot!
The WrapPanel has, as well as the StackPanel, an Orientation property, which defaults to Vertical. So your list should wrap (assuming you have enough space at hand) if your ItemsPanelTemplate looks like this:
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
About the ScrollViewer:
The desired behavior should be achieved by defining it like follows (not tested though, and I omitted all for this example unnecessary stuff):
<ScrollViewer HorizontalAlignment="Stretch">
<ItemsControl MinWidth="550" Width="{Binding ActualWidth, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ScrollViewer}}}" />
</ScrollViewer>
I think you want the WrapPanel in the ItemsPanel and the StackPanel in the ItemTemplate.
why not use the WrapPanel as ItemsPanelTemplate?
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
as long as the items have space to the left they would be arranged horizontal.
Related
I've written a code example below:
<StackPanel>
<TextBlock>Appointments today</TextBlock>
<ItemsControl ItemsSource="{Binding Appointments}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controls:CalendarMonthDayEventsItemsPanel OutsideViewportCount="..." />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border>
<TextBlock Text="{Binding Title}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<StackPanel Orientation="Horizontal">
<TextBlock>+</TextBlock>
<TextBlock Text="{Binding ......}" /> <!-- Should show number of items in ItemsControl that are outside view, using CalendarMonthDayEventsItemsPanel.OutsideViewportCount -->
<TextBlock>more items</TextBlock>
</StackPanel>
</StackPanel>
I Created a custom Panel, the CalendarMonthDayEventsItemsPanel, and I use that panel as the itemspanel of the ItemsControl. In the panel's layout code, I determine how many items (panel childs) are outside the bounds of the panel. The property OutsideViewportCount contains the number of items that are outside of the visible bounds of the CalendarMonthDayEventsItemsPanel.
Now I want to show the value of OutsideViewportCount in a TextBlock that's below the ItemsControl.
This means I have to create some kind of binding, but everything I tried doesn't work.
Does someone have a solution or a better approach to achieve the same result?
Maybe you can make use of Tag property of ItemsPanel to relay the value of ItemsPanel as a workaround.
<ItemsControl x:Name="A"
ItemsSource="{Binding Appointments}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:CalendarMonthDayEventsItemsPanel OutsideViewportCount="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=Tag, Mode=OneWayToSource}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
...
</ItemsControl>
<StackPanel Orientation="Horizontal">
<TextBlock>+</TextBlock>
<TextBlock Text="{Binding ElementName=A, Path=Tag, Mode=OneWay}"/>
<TextBlock>more items</TextBlock>
</StackPanel>
I am working on c# xaml using silverlight and i am bit confused about the hierarchy of this xaml code:
<UserControl.Resources>
<this:MyValueConverter x:Key="TabConverter"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="Green">
<ItemsControl ItemsSource="{Binding Path=TabList, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas></Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="150" Background="red" Height="100" Canvas.Left="{Binding TabList, Mode=TwoWay, Converter={StaticResource TabConverter}}" Canvas.Top="100" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
When i run it gives a big green color window(sorry if technical names are not correct), whereas it should also show red color somewhere in same window as it has Border Width="150" Background="red" .Could some one please explain me what this code is doing ?
ItemsControl really just binds to a list and applies a datatemplate (border with background red) for each item in the list. As for the reason you're only seeing green, well there's probably nothing in the TabList property on your viewmodel. That way, nothing in the items template renders, and all you see is green.
You'll need to make sure that TabList is bound correctly (it exists on your datacontext, whether that's a view model or not) and that it has items in it.
Here's a simpler version of what you may want to accomplish:
<Grid x:Name="LayoutRoot" Background="Green">
<ItemsControl ItemsSource="{Binding Path=TabList, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="150" Background="red" Height="100" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
When I'm placing a semantic zoom control with GridView inside my items are falling out of it as on the screenshot.
I put my data items into a wrap panel and expecting it will wrap them. But for some reason it does not. What is wrong here?
Here is how my gridview defined in xaml:
<SemanticZoom.ZoomedInView>
<GridView ScrollViewer.IsHorizontalScrollChainingEnabled="False"
ScrollViewer.IsVerticalScrollChainingEnabled="False"
ItemTemplate="{StaticResource PatientMediaFileBigItemTemplate}"
ItemsSource="{Binding Source={StaticResource patientMediaFiles} }"
IsItemClickEnabled="True"
SelectionMode="None"
Margin="0,0,0,0" ItemClick="MediaFileIcon_Click"
>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<controls:WrapPanel Orientation="Vertical" FlowDirection="LeftToRight" Width="Auto"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding GroupName}" FontSize="28" Foreground="Black"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
</SemanticZoom.ZoomedInView>
I think this is because of your wrap panel you need to do calculations according to your requirement in arrangeOverride and measureOverride method and try to set the child items viewport and its offset.
I solved the issue by adding group style along group header style
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,10,0"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
I have two user controls, WorkflowTileItemsControl and WorkflowTileControl. The WorkflowTileItemsControl hosts the WorkflowTileControl in an ItemsControl. However, there are dependency properties on the WorkflowTileControl that I would like to expose to anything using the WorkflowTileItemsControl. In order to do that here is ItemsControl code for WorkflowTileItemsControl.
<ItemsControl ItemsSource="{Binding Source={StaticResource WorkflowTilesViewSource}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding WorkflowTileControl, ElementName=ctrlWorkflowTileItems}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
However this doesn't seem to work. It is only showing the last item in the ItemsControl. Below is code that works, and is the functionality I'm looking for (minus hard coding all the dependency properties).
<ItemsControl ItemsSource="{Binding Source={StaticResource WorkflowTilesViewSource}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<OrderCommon:WorkflowTileControl IsReadOnly="True" Margin="5" TasksTitle="Defects" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And this is what my calling code looks like.
<OrderCommon:WorkflowTileItemsControl WorkflowRequirementTypeCode="DISBURSEMENTDFCT" Margin="5" MinWidth="1000" MaxWidth="1250" HorizontalAlignment="Left">
<OrderCommon:WorkflowTileItemsControl.WorkflowTileControl>
<OrderCommon:WorkflowTileControl IsReadOnly="True" Margin="5" TasksTitle="Defects" />
</OrderCommon:WorkflowTileItemsControl.WorkflowTileControl>
</OrderCommon:WorkflowTileItemsControl>
I feel like there is some simple step I'm missing. I'm not sure if ContentPresenter is the right tool for the job. I haven't done anything like this in WPF before. Can someone please assist?
So after some days of research I've found a solution. The WorkflowTileItemsControl needs to expose a Dependency Property of a DataTemplate which will be bound to the ItemsTemplate for the ItemsControl. Here is the xaml for the WorkflowTileItemsControl:
<ItemsControl ItemsSource="{Binding Source={StaticResource WorkflowTilesViewSource}}" ItemTemplate="{Binding WorkflowTileTemplate, ElementName=ctrlWorkflowTileItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
And Here is the xaml for the calling control:
<OrderCommon:WorkflowTileItemsControl WorkflowRequirementTypeCode="DISBURSEMENTDFCT" Margin="5" Width="1130" HorizontalAlignment="Left">
<OrderCommon:WorkflowTileItemsControl.WorkflowTileTemplate>
<DataTemplate>
<OrderCommon:WorkflowTileControl IsReadOnly="True" Margin="5" TasksTitle="Defects" />
</DataTemplate>
</OrderCommon:WorkflowTileItemsControl.WorkflowTileTemplate>
</OrderCommon:WorkflowTileItemsControl>
I have the following XAML which produces a vertical output of several TextBlocks and ListBoxes, however I want to change it so that it will go horizontally.
<StackPanel>
<TextBlock Margin="5" Text="Collated Results" FontWeight="Bold"
VerticalAlignment="Center" DockPanel.Dock="Top"/>
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto" CanContentScroll="True">
<ItemsControl x:Name="lstCollatedSensorData">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Margin="5" Width="100" Text="{Binding Name}"/>
<ListBox Margin="5" Width="100"
ItemsSource="{Binding CollatedResults}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</StackPanel>
The Textbox and Listbox in the StackPanel show correctly individually, however, each iteration is placed on top of each other, where I want them to be placed side by side horizontally. I have tried inserting WrapPanels in various locations without success, so there is obviously something that I am missing. It almost seems like the ScrollViewer is forcing the ItemsControl to be vertical rather than horizontal.
Put a stackpanel with orientation horizontal in the ItemsControl's ItemsPanel
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
Try setting Orientation on the stackpanel like so
StackPanel Orientation="Horizontal"