Setting visiblity to section of data template in a listview - c#

I have a WPF/MVVM application. When a item is selected in my listview I have a section of the datatemplate I want to be visible, then when a different item is selected it will be collapsed, and the new item will be visible. I will mock up some code below to help show what I am trying to do.
My question is how to do this for just the selected item staying in the bounds of mvvm. I know I can bind to a property in my viewmodel, but if every item has the same binding they all open, I need it to be for just the selected item and I'm not sure the best way to deal with this in MVVM, looking for suggestions. The item source in my listview is a ObservableCollection of a class that stores some default data I need when the item is selected.
<ListView Name="lvMain"
ItemsSource="{Binding MyItemSource, Mode=TwoWay}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding MyPath, Mode=TwoWay}" />
<!-- removing the rest to keep this short -->
</Grid>
<!-- This section below is collapsed by default, when selected I'd like to set the visibility, my question is how to only set the visibility in the grid below when the item is selected -->
<Grid Grid.Row="1" Visibility="{Binding ??}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- removing the rest to keep this short -->
</Grid>
</Grid>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

First you'll need some boolean to visibility converter but you can use built in one if you don't have yours and then you need to use RelativeSource binding to go up the visual tree, find ListViewItem and bind to its IsSelected property via that converter
<ListView Name="lvMain" ...>
<ListView.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</ListView.Resources>
<ListView.ItemTemplate>
<DataTemplate>
<!-- removed content -->
<Grid
...
Visibility="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}},
Path=IsSelected,
Converter={StaticResource BooleanToVisibilityConverter}}">
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Related

Using an ItemsControl inside of a ListView ItemTemplate with XAML

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, }
};

WP8.1 Popup - Slow to render

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.

Winrt - Specific ItemTemplate on last item of ListView

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.

WPF ContentControl not showing user control (which should be bound by DataContext)

I have a UserControl which contains a ContentControl, which in turn should present a UserControl depending on the view model which is set as DataContext.
The XAML:
<UserControl.Resources>
<DataTemplate DataType="{x:Type pcViewModels:SystemPCViewModel}">
<controls:SystemPCControl />
</DataTemplate>
<DataTemplate DataType="{x:Type pcViewModels:ChipPCViewModel}">
<controls:ChipPCControl />
</DataTemplate>
<!-- Left out other definition, I guess you get the point -->
</UserControl.Resources>
<Grid Background="Aqua">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ScrollViewer Background="Blue">
<ContentControl DataContext="{Binding CurrentContent}"/>
</ScrollViewer>
<StackPanel
Grid.Row="1"
Orientation="Horizontal" FlowDirection="RightToLeft">
<Button
Width="150" Height="50"
Content="Configure"
VerticalAlignment="Center"
Command="{Binding CurrentContent.ConfigureCommand}" />
</StackPanel>
</Grid>
I made the backgrounds of the Grid and ScrollViewer ugly visible just to be sure it was visible. So that's all visible, I can see that the view model is as DataContext (the button is also working fine).
I used a ContentControl before, and to all my knowledge exactly like this. What am I doing wrong?
You must set the Content property of your ContentControl. You can do either of the following:
<ContentControl DataContext="{Binding CurrentContent}" Content="{Binding}" />
or
<ContentControl Content="{Binding CurrentContent}" />

what is the best way to bind ListView (WPF) with same icon for each item

I have a list view that is binded to some object I've created.
The binding is working perfect, but I want to add icon to each item in my list.
All the items should have the SAME icon (should be defined prior as "file.ico").
What is the best to implement this?
Thanks.
Use an ItemTemplate, e.g:
<ListBox ItemsSource="{Binding MyItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="/Images/.." Width=".." Height=".." />
<TextBlock Grid.Column="1" Text="{Binding Name}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You should use a ListBox unless you have a specific reason to use a ListView.

Categories

Resources