So, a bit of a crazy request. I need a list of items, which I plan to use a ListView for, but inside each element, I need another "List" so-to-speak that will expand horizontally.
Here is a crude drawing of the basic idea I'm going for:
For my code, this is what I've tried, but it's not working. (And yes, I'm purposely not using binding yet so I can just use the design view to get everything looking right)
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Grid.IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="KpiColumn0" />
<ColumnDefinition Width="Auto" SharedSizeGroup="KpiColumn1" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical" Grid.Row="0" Grid.Column="0">
<TextBlock Text="Test" />
<TextBlock Text="Test" FontSize="8" Margin="0,-4,0,0" />
</StackPanel>
<TextBlock Grid.Row="0" Grid.Column="2" Text="Test" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Test" />
<TextBlock Grid.Row="1" Grid.Column="2" Text="Test" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Items>
<MenuItem />
</ListView.Items>
</ListView>
How can I use a ListView to hold a list of items in each of its item, that expand horizontally, based on how many elements are in the List that each ListItem is bound to?
Add this to your inner ItemsControl and the items will be shown in horizontal alignment.
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
Note that you won't be able to use the designer view for this. You'll need to remove the ListView.Items that you have, and instead use binding or code-behind to have it show when running.
Something like this should work, if you give the ListView a Name of LV:
LV.ItemsSource = new List<List<int>>
{
new List<int> {1,2,3,4, },
new List<int> {1,2,3,4, }
};
Related
I have a Usercontrol that contains a ListView, Add Button and a ComboBox. The intention is that when a user clicks Add the selected item in the ComboBox is added to the ListView.
This functionality works fine, however it would be great if the item in the ComboBox was removed list as duplicates aren't allowed in the ListView. Currently I am handling this in the ViewModel, but that means I have to implement the same code for each instance of the UserControl
Does anyone have a good idea how to implement a generic solution for this problem?
<UserControl>
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListView x:Name="ListView"
ItemsSource="{x:Bind ListViewItemsSource}"
SelectedItem="{x:Bind ListViewSelectedItem, Mode=TwoWay}"
ItemTemplate="{x:Bind ListViewItemTemplate}"
Style="{x:Bind ListViewStyle}"
Margin="{StaticResource MediumBottomMargin}"
Visibility="{x:Bind ListViewVisibility, Mode=TwoWay}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<uwptoolkit:WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
<StackPanel Grid.Row="1"
Orientation="Horizontal">
<ComboBox x:Name="ComboBox"
Style="{StaticResource StandardComboStyleFixedWidth}"
ItemsSource="{x:Bind ComboBoxItemsSource, Mode=OneWay}"
SelectedItem="{x:Bind ComboBoxSelectedItem, Mode=TwoWay}"
DisplayMemberPath="{x:Bind ComboBoxDisplayMemberPath}"
PlaceholderText="{x:Bind ComboBoxPlaceholderText}"
BorderBrush="{x:Bind ComboBoxBorderBrush, Mode=TwoWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ComboBox>
<Button x:Name="AddButton"
Style="{StaticResource AddButtonStyle}"
Click="AddButton_Click"
IsEnabled="{x:Bind AddButtonIsEnabled, Mode=TwoWay}"/>
</StackPanel>
</Grid>
</UserControl>
EDIT:
I should add that I didn't create this class, I have inherited it and am looking to improve it. I will implement the style changes suggested.
What I mean by code behind is this:
<uc:ListTagControl
ComboBoxItemsSource="{x:Bind _viewModel.TypeItems, Mode=TwoWay}"
ComboBoxSelectedItem="{x:Bind _viewModel.SafetyType, Mode=TwoWay}"
ComboBoxDisplayMemberPath="Type"
ListViewSelectedItem="{x:Bind _viewModel.SelectedListViewItem, Mode=TwoWay}"
ListViewItemsSource="{x:Bind _viewModel.Safeties, Mode=TwoWay}"
AddButtonOnClick="{x:Bind _viewModel.AddType}"
AddButtonIsEnabled="True" />
In the ViewModel it will then do this, to remove the item from the combobox:
TypeItems.Remove(TypeItems
.Where(i => i.Id == _Safety.SafetyType.Id).Single());
I want to move this as a generic implementation into the xaml.cs
I am creating UWP application. There is a listview, with groups.
XAML code goes like this:
<Page.Resources>
<CollectionViewSource x:Name="ContactsCVS" IsSourceGrouped="True" />
<!-- 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>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListView ItemsSource="{x:Bind ContactsCVS.View}"
ItemTemplate="{StaticResource ContactListViewTemplate}"
SelectionMode="Single"
ShowsScrollingPlaceholders="True"
Grid.Row="1"
Grid.ColumnSpan="2" x:Name="listViewMain">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate x:DataType="data:GroupInfoList">
<TextBlock Text="{x:Bind Key}"
/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
</Grid>
And everything is ok, except that I want to make each group to have some kind of border. Like this:
How to achieve this?
As #Ken Tucker said, you can edit the GroupStyle and use GroupStyle.Panel property to add a border for each group. For example, using a GroupStyle like the following:
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate x:DataType="data:GroupInfoList">
<TextBlock Text="{x:Bind Key}"
Style="{ThemeResource TitleTextBlockStyle}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<StackPanel BorderBrush="Red" BorderThickness="1" Margin="8,0,18,0" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
However, you may find there is no effect with using this GroupStyle in your code. This is because GroupStyle.Panel can't work with UI virtualization. If the ListView uses a virtualizing panel such as ItemsWrapGrid or ItemsStackPanel, then GroupStyle.Panel won't have effect. And for ListView its default ItemsPanel is a ItemsStackPanel. So you will also need to change ListView's ItemsPanel like:
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
Then you should be able to see the border for each group. For more info, please refer to this case. And also please note that using GroupStyle.Panel might influence the performance as the lack of UI virtualization. You may consider whether to use this according to your real scenario.
I made a popup control that can accept any view of type FrameworkElement. In addition, you can provide a view model, which will be bound to the DataContext of the child view being provided. Everything works, but it takes a couple of seconds to render the data. The view model has an ObservableCollection that contains about 300 items. So in all honesty, 300 items shouldn't cause any issues.
There is no lag what so ever, If I extract the xaml from the popup to a regular page.
So, is there something inside a Popup control that happens when it's Child content property is being set, that would cause such a delay? Because this is blowing my mind at the moment.
Thanks in advance!
[Update]
As requested, the XAML that forms the child content of the tool window:
<UserControl
x:Class="App.Controls.ContactSelector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
mc:Ignorable="d" x:Name="contactSelector"
DataContext="{Binding ContactSelectorViewModel,Source={StaticResource Locator}}">
<Grid HorizontalAlignment="Stretch" Style="{StaticResource BaseGridStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListView Grid.Row="0" ItemsSource="{Binding ContactCollection}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<!--<Image Margin="0,0,10,0" Grid.Row="0" Grid.Column="0"
Source="{Binding Thumbnail}" MaxHeight="35"
Visibility="{Binding Thumbnail, Converter={StaticResource ObjectNullToVisibilityConverter}}" />-->
<!--<Image Margin="0,5,5,5" Grid.Row="0" Grid.Column="0" MaxHeight="35"
Source="ms-appx:///Assets/Images/Contact.png"
Visibility="{Binding Thumbnail, Converter={StaticResource InverseObjectNullToVisibilityConverter}}" />-->
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding FullName}"
VerticalAlignment="Center"
Style="{StaticResource TextBlockMedium}" />
<!--<Grid Grid.Row="1" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ItemsControl Grid.Row="0" ItemsSource="{Binding MobileNumbers}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="0"
Text="{Binding Number}"
HorizontalAlignment="Stretch"
Style="{StaticResource TextBlockMedium}">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Tapped">
<core:InvokeCommandAction
Command="{Binding DataContext.SelectContact, ElementName=contactSelector}"
CommandParameter="{Binding}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</TextBlock>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>-->
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<!--<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Border>
<TextBlock Text="{Binding Key}"
VerticalAlignment="Center" HorizontalAlignment="Center"
Style="{StaticResource TextBlockMedium}"
Padding="5" Margin="5" FontWeight="SemiBold" />
</Border>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>-->
</ListView>
</Grid>
</UserControl>
So I have commented out the entire section of the ItemsControl, but this did not solve the problem. When the Popup opens, it still takes quite a while to show the containing items.
It isn't slow when it's scrolling, it's slow in rendering the initial items.
The problem is in the ItemsControl which displays the MobileNumbers collection. You should not have an ItemsControl as an ItemTemplate for another ItemsControl (in your case, the ListView). You can do that only when you display small amount of items.
Because of this your MobileNumbers items are not virtualized and this is where the performance problem comes from, as all the items need to be displayed to render the item template.
You can try creating a flat list of objects, and then use ItemTemplateSelector to display different item templates for different types. For example you could have the following ObservableCollection as the ItemsSource:
Header
Contact info
Mobile number1
Mobile number2
Header
Contact info
Mobile number
etc.
I have this list view on a windows store app project
<ListView ItemsSource="{Binding Attachments}" IsItemClickEnabled="False" SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate >
<Grid Width="280" Height="50" Margin="85,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="5" />
</Grid.RowDefinitions>
<RadioButton GroupName="meetingFiles" Content="TESTE" Style="{StaticResource RadioButtonStyle1}"></RadioButton>
<TextBlock Text="1" HorizontalAlignment="Right"></TextBlock>
<Grid x:Name="whiteLine" Grid.Row="1" Width="270" Height="1" Background="White" HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
i want that my last item on the listview dont show the grid named whiteLine
how can i do that? or is it impossible?
An alternative solution would be to add a Listview.footer as so:
<ListView>
<!-- Your Listview ItemTemplate /-->
<ListView.Footer>
<Grid Width="280" Height="50" Margin="85,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="5" />
</Grid.RowDefinitions>
<RadioButton GroupName="meetingFiles" Content="TESTE" Style="{StaticResource RadioButtonStyle1}"></RadioButton>
<TextBlock Text="1" HorizontalAlignment="Right"></TextBlock>
</ListView.Footer>
</ListView>
This isn't really changing the last item, it is adding an element that is always at the bottom of the ListView, and looks the same as your items. This will give the user the impression that it is part of the listview, and you will keep your code simple.
Either
<ListView ItemTemplateSelector="..."/>
Or binding the Grid's Visibility would do the trick. But you would need some type of flag variable in your Model such that you can use that to determine if it is the last one in the list.
I used the above solution to alternate the background color of each item in the ListView, with my Model containing a RowID as well.
I'm trying to build a kind of Wizard with a ScatterViewItem. In the lower area are buttons for Next, Back and Cancel. When pressing on the Next or Back button the upper part should show the next 'page'. I've tried using a DataTemplate, but the DataTemplate is not showing in the upper area. I get only a blank area.
I'm still new to WPF and Surface and maybe try something that did not work. May you have better ideas.
Here's the code:
<s:SurfaceWindow.Resources>
<DataTemplate x:Key="LoadProject">
<StackPanel Orientation="Vertical">
<Label Name="lbl_Database" Content="Database" />
<s:SurfaceTextBox Name="txt_Database"/>
<Label Name="lbl_Project" Content="Project" />
<s:SurfaceTextBox Name="txt_Project"/>
</StackPanel>
<DataTemplate x:Key="LoadProject">
</s:SurfaceWindow.Resources>
<s:ScatterView>
<s:ScatterViewItem Width="300" Height="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<ItemsControl x:Name="DynamicArea" ItemTemplate="{StaticResource LoadProject}" Grid.Column="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<StackPanel Orientation="Horizontal" Grid.Row="1">
<s:SurfaceButton Name="btn_Next" Content="Next" />
<s:SurfaceButton Name="btn_Back" Content="Back" />
<s:SurfaceButton Name="btn_Cancel" Content="Cancel" />
</StackPanel>
</Grid>
</s:ScatterViewItem>
</s:ScatterView>