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

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}" />

Related

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.

Setting visiblity to section of data template in a listview

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>

wpf - Data Template, change template with button

my task is to make DataTemplate list, and create a button for changing the view.
I have the "Data" and "FootballTeam" classes, and also I have the Static Resources. I need help for the button event, how can I change the current template?
As a tip, the example says to use this method:
"this.Resources[resource-key] as data-type;"
The XAML:
<Window x:Class="WpfApplication11.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="250"
Width="300">
<Window.Resources>
<DataTemplate x:Key="teamName">
<TextBlock FontWeight="Bold"
Text="{Binding Path=TeamName}"></TextBlock>
</DataTemplate>
<DataTemplate x:Key="year">
<TextBlock Text="{Binding Path=FoundingYear}"></TextBlock>
</DataTemplate>
<DataTemplate x:Key="logo">
<Image Source="{Binding Path=Image}" />
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0"
AllowDrop="True">
<ListBox Name="lstTeams">
</ListBox>
</ScrollViewer>
<Button Grid.Row="1"
Margin="6">Change View</Button>
</Grid>
</Window>
I guess you want to change the listbox template so, try this :
In XAML
<Button Grid.Row="1" Margin="6" Click="changeTemplate">Change View</Button>
In C#
lstTeams.ItemTemplate = (DataTemplate)this.Resources["teamname"];
You have to handle the different templates you want to cycle through but, this is pretty much how to do it code-behind.

WPF - FrameworkElement - Enumerate all decendents?

I have a FrameworkElement (really a ToggleButton) that has inside its content a Popup.
I access it like this:
ToggleButton button = (ToggleButton)sender;
Popup popup = (Popup)button.FindName("popSelectIteration");
Usually this works fine. But sometimes popup is null.
I am trying to find a way to debug this. Is there a way enumerate all the "things" that FindName could find?
As background, here is how my popup is defined in the ToggleButton:
<ToggleButton Grid.Column="1" HorizontalAlignment="Right" Margin="0,2,0,2" Checked="btnFindIterationChecked">
<Grid>
<Popup PlacementTarget="{Binding ElementName=chkIteration}" Name="popSelectIteration" Closed="popSelectIteration_Closed"
AllowsTransparency="True" StaysOpen="False" PopupAnimation="Fade">
<Border BorderBrush="#FF000000" Background="LightBlue" BorderThickness="1,1,1,1" CornerRadius="8,8,8,8" Padding="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="300"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Foreground="Black" >Select Destination:</TextBlock>
<ScrollViewer Grid.Row="1" >
<TreeView ItemsSource="{Binding IterationTree}" SelectedItemChanged="TreeView_SelectedItemChanged">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding PathEnd}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</ScrollViewer>
<Button Grid.Row="2" Background="LightBlue" Content="Clear Selection" Click="btnClear_Click"/>
</Grid>
</Border>
</Popup>
</Grid>
</ToggleButton>
Try Snoop. It is a great WPF debugging utility for everything that concerns the visual tree.
Edit: Your specific problem seems to be a timing issue though. I guess that the tree is not completely constructed yet and you try to access a child element although it is not created. Wait until the topmost element receives a "Loaded" event.

Categories

Resources