I want to create a grid like this:
I decided to use instead of a grid 6 listview, my problem is that the loading of pages is very slow.
Here is the code (obscene):
I created a user control:
namespace ProjectVea.Support
{
public sealed partial class Control1: UserControl
{
public ObservableCollection<Support.Ora> coll { get; private set; } = new ObservableCollection<Support.Ora>();
public Control1()
{
this.initializeCollection();
this.InitializeComponent();
}
private void initializeCollection()
{
Ora ite;
for(int i = 0; i < 19; i++)
{
ite = new Ora(i.ToString());
coll.Add(ite);
}
}
}
}
in xaml I simply duplicated the listview:
<UserControl>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<ListView Name="list0" ItemsSource="{x:Bind coll}" SelectionMode="None" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Ora">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{x:Bind descrizione}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<StackPanel Grid.Column="1">
<ListView Name="list1" ItemsSource="{x:Bind coll}" SelectionMode="None" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Ora">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{x:Bind descrizione}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<StackPanel Grid.Column="2">
<ListView Name="list2" ItemsSource="{x:Bind coll}" SelectionMode="None" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Ora">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{x:Bind descrizione}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<StackPanel Grid.Column="3">
<ListView Name="list3" ItemsSource="{x:Bind coll}" SelectionMode="None" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Ora">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{x:Bind descrizione}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<StackPanel Grid.Column="4">
<ListView Name="list4" ItemsSource="{x:Bind coll}" SelectionMode="None" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Ora">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{x:Bind descrizione}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<StackPanel Grid.Column="5">
<ListView Name="list5" ItemsSource="{x:Bind coll}" SelectionMode="None" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Ora">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{x:Bind descrizione}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Grid>
</UserControl>
ora class:
namespace ProjectVea.Support
{
public class Ora
{
public string descrizione { get; set; }
public Ora(string descrizione)
{
this.descrizione = descrizione;
}
}
}
There are techniques to use xaml in the most efficient?
why not try something like this
<ListView ItemsSource="{Binding Items}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid MaximumRowsOrColumns="6" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="Name" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Related
I have a model view and a property called isEnable and I would like to set the comboboxItem IsEnable property with binding to property created in the model view , the problem is that I have datatemplate created inside a combobox , so it's not a simple Combobox , this is my code:
<ComboBox x:Name="ComboBoxUsers" ItemsSource="{Binding Users}" FontFamily="Arial" FontSize="11" Grid.Row="3" Height="30" Margin="10,5,5,5">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Image />
<TextBlock />
</StackPanel>
<DataTemplate.Resources>
<Style TargetType="ComboBoxItem">
<Setter Property="IsEnable" Value="{Binding IsEnable}"/>
</Style>
</DataTemplate.Resources>
</DataTemplate>
</ComboBox.ItemTemplate>
Simple Class of Users:
public class Users
{
public string Name { get; set; }
public bool IsEnable { get; set; }
public Users()
{
}
}
How can I achieve that?
I solved my problem by adding this code :
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem"
<Setter Property="IsEnable" Value="{Binding IsEnable}" />
</Style>
</ComboBox.ItemContainerStyle>
So the complete code will be :
<ComboBox x:Name="ComboBoxUsers" ItemsSource="{Binding Users}" FontFamily="Arial" FontSize="11" Grid.Row="3" Height="30" Margin="10,5,5,5">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Image />
<TextBlock />
</StackPanel>
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem" >
<Setter Property="IsEnable" Value="{Binding IsEnable}" />
</Style>
</ComboBox.ItemContainerStyle>
</DataTemplate>
</ComboBox.ItemTemplate>
Universal Windows Platform, C#
How can I collapse/expand the child listview of item MainListView listitem from code behind? I have not found anything that works.
I'd like to do this on the SelectionChanged event.
XAML
<ListView x:Name="DestListView" SelectionMode="Single" Margin="0,60,0,0" SelectionChanged="listview_SelectionChanged" >
<ListView.ItemContainerStyle >
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="BorderThickness" Value="0,.5,0,0" />
<Setter Property="BorderBrush" Value="Gainsboro" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate >
<DataTemplate>
<StackPanel>
<Grid>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" MinWidth="20" />
<TextBlock Grid.Column="1" Text="{Binding destination}" FontSize="20" />
<TextBlock Grid.Column="2" Text="{Binding total_quantity}" FontSize="20" Margin="10,0,0,0"/>
<TextBlock Grid.Column="3" Text="{Binding package_type}" FontSize="20" HorizontalAlignment="Center" Margin="10,0,0,0"/>
<TextBlock Grid.Column="4" Text="{Binding total_weight}" FontSize="20" Margin="10,0,0,0"/>
</Grid>
</Grid>
**<!--Collpase/Expand-->**
<ListView x:Name="DetailListView" ItemsSource="{Binding destination_data}" SelectionMode="Multiple" Margin="20,0,0,0" Visibility="Collapsed" >
<ListView.ItemTemplate >
<DataTemplate >
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding visual_number}" FontSize="14" Foreground="White" HorizontalAlignment="Stretch" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
CodeBehind
private void listview_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//GET THE ITEM
var selectItem = DestListView.Items[DestListView.SelectedIndex];
//GET THE CHILD SOMEHOW
//ListView childListView = (ListView)...not sure what to do here
//if (childListView != null)
//{
// if (childListView.Visibility == Visibility.Collapsed)
// {
// //childListView.Visibility = Visibility.Collapsed;
// }
// else
// {
// //childListView.Visibility = new Visibility;
// }
//}
}
Here is how i would do it.
I would create two DataTemplates one to show when selected (Expanded), another when not expanded.
Below is my ViewModel.
public class MyViewModel
{
public MyViewModel()
{
myItems = new ObservableCollection<MyItems>();
for(int i=1;i<=10;i++)
{
MyItems item = new MyItems();
item.Name = "Main Item " + i.ToString();
ObservableCollection<MySubItems> subItems = new ObservableCollection<MySubItems>();
for (int j=1;j<=5;j++)
{
subItems.Add(new MySubItems() { Title = "Sub Item " + j.ToString() });
}
item.Data = subItems;
myItems.Add(item);
}
}
public ObservableCollection<MyItems> myItems { get; set; }
}
public class MyItems
{
public string Name { get; set; }
public ObservableCollection<MySubItems> Data { get; set; }
}
public class MySubItems
{
public string Title { get; set; }
}
Below is my MainPage.xaml as requested
<Page
x:Class="App2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.DataContext>
<local:MyViewModel/>
</Page.DataContext>
<Page.Resources>
<DataTemplate x:Key="NoSelectDataTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Name}" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="SelectDataTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Name}" />
<ListView ItemsSource="{Binding Data}" Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding myItems}" SelectionChanged="ListView_SelectionChanged" ItemTemplate="{StaticResource NoSelectDataTemplate}">
<ListView.ItemContainerStyle >
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="BorderThickness" Value="0,.5,0,0" />
<Setter Property="BorderBrush" Value="Gainsboro" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
</Page>
And Below is how my SelectionChanged Event Looks like.
private int PreviousIndex;
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView lv = sender as ListView;
if (PreviousIndex >=0)
{
ListViewItem prevItem = (lv.ContainerFromIndex(PreviousIndex)) as ListViewItem;
prevItem.ContentTemplate = Resources["NoSelectDataTemplate"] as DataTemplate;
}
ListViewItem item = (lv.ContainerFromIndex(lv.SelectedIndex)) as ListViewItem;
item.ContentTemplate = Resources["SelectDataTemplate"] as DataTemplate;
PreviousIndex = lv.SelectedIndex;
}
Here is the Output
I have a Listview inside a Listview as you can see in my code. I am trying to collapse other categories when i open another. Is that possible? I have tried many things but I don't know how to access elements in other row...
<ListView x:Name="MainListView"
ItemsSource="{x:Bind menu}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:MainCategories">
<Grid Background="blue">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock x:Name="test"
Text="{x:Bind CategoryName}"
Tapped="Category_TextBlock_Tapped"
FontSize="25" />
<Grid Grid.Row="1"
Name="tittleGrid"
Background="Gray">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Name"
HorizontalAlignment="Center" />
<Border BorderBrush="Black"
BorderThickness="1,0,1,0"
Grid.Column="1">
<TextBlock HorizontalAlignment="Center"
Text="Price" />
</Border>
<TextBlock Text="QUantity"
Grid.Column="2"
HorizontalAlignment="Center" />
</Grid>
<ListView x:Name="SubListView"
Grid.Row="2"
Background="YellowGreen"
ItemsSource="{x:Bind SubMenuItems}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
<Setter Property="Padding"
Value="0" />
<Setter Property="VerticalContentAlignment"
Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:Dishes">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center"
Text="{x:Bind dishName}"
HorizontalAlignment="Center" />
<Border BorderBrush="Black"
BorderThickness="1,0,1,0"
Grid.Column="1">
<TextBlock VerticalAlignment="Center"
Grid.Column="1"
HorizontalAlignment="Center"
Text="{x:Bind dishPrice}" />
</Border>
<TextBlock Grid.Column="2"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Text="{x:Bind dishPrice}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And here is the toggle-visibility method i have made and works fine for the one i am clicking but I want to collapse ALL the others when i expand the one i click... I might have many mistakes in my code but I'm kinda new to UWP
private void Category_TextBlock_Tapped(Object sender, TappedRoutedEventArgs e)
{
CloseAllOthers();
TextBlock categoryName = sender as TextBlock;
Grid grid = (categoryName.Parent as Grid);
ToggleVisibility(grid);
}
private void ToggleVisibility(Grid grid)
{
foreach (var gr in grid.Children)
{
if (gr.GetType() == grid.GetType() || gr.GetType() == MainListView.GetType())
{
if (gr.Visibility == Visibility.Visible)
{
gr.Visibility = Visibility.Collapsed;
}
else
gr.Visibility = Visibility.Visible;
}
}
}
My result so far
and the collapsed version
Here's a simplified example of what you want to do:
<ListView x:Name="menu" ItemsSource="{x:Bind MenuItems}" IsItemClickEnabled="True" ItemClick="onItemClick">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<!-- Disable virtualization -->
<StackPanel/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="MinHeight" Value="0"/>
</Style>
</ListView.Resources>
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:MenuItem">
<StackPanel>
<TextBlock Text="{x:Bind Text}" FontWeight="Bold" Margin="10,10,0,10"/>
<ListView x:Name="subMenu" ItemsSource="{x:Bind SubItems}" Visibility="Collapsed">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:MenuItem">
<TextBlock Margin="20,5,0,5" Text="{x:Bind Text}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
public class MenuItem
{
public string Text { get; set; }
public List<MenuItem> SubItems { get; set; }
}
public sealed partial class MainPage : Page
{
public List<MenuItem> MenuItems { get; }
public MainPage()
{
InitializeComponent();
MenuItems = Enumerable.Range(1, 3).Select(i => new MenuItem()
{
Text = $"Menu item {i}",
SubItems = Enumerable.Range(1, 3).Select(j => new MenuItem()
{
Text = $"Sub item {i}.{j}",
}).ToList(),
}).ToList();
}
private void onItemClick(object sender, ItemClickEventArgs e)
{
foreach (var item in menu.Items)
{
var container = (ListViewItem)menu.ContainerFromItem(item);
if (container != null)
{
var subMenu = (container.ContentTemplateRoot as FrameworkElement)?.FindName("subMenu") as FrameworkElement;
if (subMenu != null)
{
subMenu.Visibility = e.ClickedItem == item ? Visibility.Visible : Visibility.Collapsed;
}
}
}
}
}
I wouldn't necessarily recommend this approach; I prefer more of a data-driven approach with bindings to control the visibility of the sub menus when the parent list item is selected, rather than accessing the view directly, but this is fine for simple scenarios.
I have a list of chats on the left and messages for a given chat on the right.
I want to have the MessageList to scroll to the bottom whenever it appears or gets its data updated. How can I do this?
My code is based off of Microsoft's Master/Detail view example:
https://github.com/Microsoft/Windows-universal-samples/blob/master/Samples/XamlMasterDetail/cs/MasterDetailPage.xaml
The xaml page:
<Page
x:Class="MyApp.Pages.ChatsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyApp.Pages"
xmlns:data="using:MyApp.Model.Profile"
xmlns:vm="using:MyApp.ViewModel"
xmlns:util="using:MyApp.Util"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Transitions>
<TransitionCollection>
<NavigationThemeTransition />
</TransitionCollection>
</Page.Transitions>
<Page.Resources>
<util:BoolToVisibilityConverter x:Key="BoolToVisConverter" />
<!--CollectionViewSource x:Name="Chats"
Source="{x:Bind ViewModel}"/>
<CollectionViewSource x:Name="Chat"
Source="{Binding ChatViewModel, Source={StaticResource Chats}}"/>
<CollectionViewSource x:Name="Messages"
Source="{Binding MessageViewModel, Source={StaticResource Chat}}"/-->
<DataTemplate x:Key="MasterListViewItemTemplate" >
<Grid Margin="0,11,0,13" BorderBrush="Gray" BorderThickness="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding ChatName}" Style="{ThemeResource ChatListTitleStyle}" />
<TextBlock
Text="{Binding LastMessage}"
Grid.Row="1"
MaxLines="1"
Style="{ThemeResource ChatListTextStyle}" />
<TextBlock
Text="{Binding LastSender}"
Grid.Column="1"
Margin="12,1,0,0"
Style="{ThemeResource ChatListLastSenderStyle}" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="DetailContentTemplate">
<ListView x:Name="MessageList" ItemsSource="{Binding Messages}" ScrollViewer.VerticalScrollMode="Auto">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel BorderBrush="Black" BorderThickness="1" Padding="1">
<TextBlock Text="{Binding Message}" Style="{StaticResource NewsfeedTextStyle}"/>
<Image Visibility="{Binding Path=IsPhoto, Converter={StaticResource BoolToVisConverter} }" Source="{Binding Photo}" />
<Image Visibility="{Binding Path=IsReaction, Converter={StaticResource BoolToVisConverter} }" Width="200" Height="200" Source="{Binding Reaction}" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Sender}" Style="{StaticResource NewsfeedTimestampStyle}" Margin="1"/>
<TextBlock Text="{Binding SentTime}" Style="{StaticResource NewsfeedTimestampStyle}" Margin="1"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</Page.Resources>
<Grid x:Name="LayoutRoot" Loaded="LayoutRoot_Loaded">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="AdaptiveStates" CurrentStateChanged="AdaptiveStates_CurrentStateChanged">
<VisualState x:Name="DefaultState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
</VisualState>
<VisualState x:Name="NarrowState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MasterColumn.Width" Value="*" />
<Setter Target="DetailColumn.Width" Value="0" />
<Setter Target="MasterListView.SelectionMode" Value="None" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="MasterColumn" Width="320" />
<ColumnDefinition x:Name="DetailColumn" Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Text="Chats"
Margin="12,8,8,8"
Style="{ThemeResource TitleTextBlockStyle}" />
<ListView
x:Name="MasterListView"
Grid.Row="1"
ItemContainerTransitions="{x:Null}"
ItemTemplate="{StaticResource MasterListViewItemTemplate}"
Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
IsItemClickEnabled="True"
ItemClick="MasterListView_ItemClick">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
<ContentPresenter
x:Name="DetailContentPresenter"
Grid.Column="1"
Grid.RowSpan="2"
BorderThickness="1,0,0,0"
Padding="24,0"
BorderBrush="{ThemeResource SystemControlForegroundBaseLowBrush}"
Content="{x:Bind MasterListView.SelectedItem, Mode=OneWay}"
ContentTemplate="{StaticResource DetailContentTemplate}">
<ContentPresenter.ContentTransitions>
<!-- Empty by default. See MasterListView_ItemClick -->
<TransitionCollection />
</ContentPresenter.ContentTransitions>
</ContentPresenter>
</Grid>
I think it's the key point that your ListView is inside of the ContentTemplate of ContentPresenter.
Usually we can use ListViewBase.ScrollIntoView(Object) method method to scroll ListView to the specific item, but when the ListView is inside of DataTemplate, it is unexposed. Here is a method, we can use VisualTreeHelper to get this ListView:
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;
}
My sample is like this:
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="MasterColumn" Width="320" />
<ColumnDefinition x:Name="DetailColumn" Width="*" />
</Grid.ColumnDefinitions>
<ListView x:Name="MasterListView" Grid.Column="0" ItemsSource="{x:Bind ChatList}" SelectionChanged="MasterListView_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:ChatEntity">
<TextBlock Text="{x:Bind Member}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ContentPresenter x:Name="DetailContentPresenter" Grid.Column="1"
Content="{x:Bind MasterListView.SelectedItem, Mode=OneWay}">
<ContentPresenter.ContentTemplate>
<DataTemplate x:DataType="local:ChatEntity">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="FromMessageDataTemplate">
<StackPanel Orientation="Horizontal" FlowDirection="LeftToRight">
<TextBlock Text="{Binding Member}" Width="30" Foreground="Blue" FontWeight="Bold" />
<TextBlock Text=":" Width="10" Foreground="Blue" FontWeight="Bold" />
<TextBlock Text="{Binding Content}" Foreground="Red" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ToMessageDataTemplate">
<StackPanel Orientation="Horizontal" FlowDirection="RightToLeft">
<TextBlock Text="Me" Width="30" HorizontalAlignment="Right" Foreground="Blue" FontWeight="Bold" />
<TextBlock Text=":" Width="10" HorizontalAlignment="Right" Foreground="Blue" FontWeight="Bold" />
<TextBlock Text="{Binding Content}" HorizontalAlignment="Right" Foreground="Green" />
</StackPanel>
</DataTemplate>
<local:ChatDataTemplateSelector x:Key="ChatDataTemplateSelector"
MessageFromTemplate="{StaticResource FromMessageDataTemplate}"
MessageToTemplate="{StaticResource ToMessageDataTemplate}" />
</Grid.Resources>
<ListView ItemsSource="{x:Bind MessageList}" ItemTemplateSelector="{StaticResource ChatDataTemplateSelector}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
The ChatEntity class and MessageEntity class are like this:
public class ChatEntity
{
public string Member { get; set; }
public ObservableCollection<MessageEntity> MessageList { get; set; }
}
public class MessageEntity
{
public enum MsgType
{
From,
To
}
public string Member { get; set; }
public string Content { get; set; }
public MsgType MessageType { get; set; }
}
and my ChatDataTemplateSelector is like this:
public class ChatDataTemplateSelector : DataTemplateSelector
{
public DataTemplate MessageFromTemplate { get; set; }
public DataTemplate MessageToTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
MessageEntity msg = item as MessageEntity;
if (msg != null)
{
if (msg.MessageType == MessageEntity.MsgType.From)
return MessageFromTemplate;
else
return MessageToTemplate;
}
return null;
}
}
Firstly I loaded the ChatList in the left ListView, and in the SelectionChanged event of the left ListView, I loaded the MessageList, this will ensure the MessageList be updated. It's like manually refreshing ObservableCollection(MessageList) for the right ListView each time you selected a item in the left ListView. But you can also add data to the MessageList in other time, and add data to it whenever there is a new message. The ObservableCollection can automatically get refresh. Here is my code:
private ObservableCollection<MessageEntity> messageList;
private ObservableCollection<ChatEntity> ChatList;
public MainPage()
{
this.InitializeComponent();
messageList = new ObservableCollection<MessageEntity>();
ChatList = new ObservableCollection<ChatEntity>();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
ChatList.Add(new ChatEntity { Member = "Tom", MessageList = messageList });
ChatList.Add(new ChatEntity { Member = "Peter" });
ChatList.Add(new ChatEntity { Member = "Clark" });
}
private void MasterListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
messageList.Clear();
for (int i = 0; i < 100; i++)
{
if (i % 2 == 0)
messageList.Add(new MessageEntity { Member = "Tom", Content = "Hello!", MessageType = MessageEntity.MsgType.From });
else
messageList.Add(new MessageEntity { Content = "World!", MessageType = MessageEntity.MsgType.To });
}
var listView = FindChildOfType<ListView>(DetailContentPresenter);
listView.ScrollIntoView(messageList.Last());
}
Data in my sample are all fake. The sample looks a little complex, but it's actually very simple, just use VisualTreeHelper to find the ListView and use its ScrollIntoView method to scroll to the last item.
I have a WPF application based on MVVM.
It has paramaters that can be set. A paramater can be a list of strings in a checkbox or a double in a numupdown. Every device has its own parameters, so the parameters are dynamically loaded. Thats why i use a DataTemplateSelector.
Xaml code
<ItemsControl ItemsSource="{Binding ParameterWrapperList}" ItemTemplateSelector="{StaticResource propertyDataTemplateSelector}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
The templates are in a resource dictionary:
<DataTemplate x:Key="doubleTemplate">
<Grid Visibility="{Binding Parameter.ParameterModel.IsVisible, Converter={StaticResource Visibility}}">
<Grid.RowDefinitions>
<RowDefinition Height="{Binding Path=RowHeight, Mode=OneWay}"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Style="{StaticResource HeaderBorderStyle}" Width="{Binding Width}" Visibility="{Binding HeaderVisibility, Converter={StaticResource Visibility}}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Parameter.DisplayName}"/>
</StackPanel>
</Border>
<Border Grid.Row="1" Style="{StaticResource ItemBorderStyle}" Width="{Binding Width}">
<telerik:RadNumericUpDown Name="nudParameterValue" Value="{Binding Path=ParameterValue, Mode=TwoWay}" Minimum="{Binding Parameter.ParameterModel.MinimumValue}" Maximum="{Binding Parameter.ParameterModel.MaximumValue}" NumberDecimalDigits="{Binding Parameter.ParameterModel.NumberDecimalDigits}" SmallChange="{Binding Parameter.ParameterModel.SmallChanges}"/>
</Border>
</Grid>
</DataTemplate>
<DataTemplate x:Key="stringTemplate">
<Grid Visibility="{Binding Parameter.ParameterModel.IsVisible, Converter={StaticResource Visibility}}">
<Grid.RowDefinitions>
<RowDefinition Height="{Binding Path=RowHeight, Mode=OneWay}"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Style="{StaticResource HeaderBorderStyle}" Width="{Binding Width}" Visibility="{Binding Path=HeaderVisibility, Converter={StaticResource Visibility}}">
<Label Content="{Binding Parameter.DisplayName}"/>
</Border>
<Border Grid.Row="1" Style="{StaticResource ItemBorderStyle}" Width="{Binding Width}" >
<ComboBox ItemsSource="{Binding Path=Parameter.ParameterModel.PossibleValues}" SelectedIndex="{Binding ParameterValue, Mode=TwoWay}">
</ComboBox>
</Border>
</Grid>
</DataTemplate>
<configControl:PropertyDataTemplateSelector
StringTemplate="{StaticResource stringTemplate}"
DoubleTemplate="{StaticResource doubleTemplate}"
x:Key="propertyDataTemplateSelector"/>
I wrote the code for the DataTemplateSelector.
public class PropertyDataTemplateSelector : DataTemplateSelector
{
public DataTemplate DoubleTemplate { get; set; }
public DataTemplate StringTemplate { get; set; }
public override DataTemplate SelectTemplate(object item,
DependencyObject container)
{
DeviceModel.ParameterType devFunct = ((ParameterWrapper)item).Parameter.ParameterModel.Type;
switch (devFunct)
{
case DeviceModel.ParameterType.Double:
return DoubleTemplate;
case DeviceModel.ParameterType.String:
return StringTemplate;
default:
return null;
}
return null;
}
}
When the applications opens all the values are set fine. But when i update ParameterValue, it isn't updated on view. (when i output the values in console window, the values are set fine (but not in the GUI)).
What should i do to make this work.
Edit
This is the code it's bound to. Every function has a checkbox and when you change the parameter of one, all other parameters that are checked need to change.
public double ParameterValue
{
get
{
return _parameter.ParameterValue;
}
set
{
Parameter.ParameterValue = value;
Console.WriteLine("ParameterValueChanged");
if (SetOthers)
{
if (_parentFunction.Checked)
{
foreach (var function in _parentFunction.FunctionWrapperList)
{
if (function.Checked)
{
foreach (var parameterWrapper in function.ParameterWrapperList)
{
if (parameterWrapper.Parameter != this.Parameter)
{
if (parameterWrapper.Parameter.ParameterModel == Parameter.ParameterModel)
{
Console.WriteLine(function.Function.Name + " " + function.Checked + " " + Parameter.ParameterValue);
parameterWrapper.SetValue(Parameter.ParameterValue);
}
}
}
}
}
}
}
Notify("ParameterValue");
}
}
private void SetValue(double parameterValue)
{
SetOthers = false;
Parameter.ParameterValue = parameterValue;
SetOthers = true;
}
The boolean SetOthers is so he won't get a stackoverflow and keeps setting itself.
Your DataTemplateSelector won't update the DataTemplate rendering your data because a DataTemplateSelector doesn't trigger on a property change. It only choose a way to display a data according to its type (yourData.GetType()).
What you want is a trigger:
<ItemsControl ItemsSource="{Binding ParameterWrapperList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource doubleTemplate}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Parameter.ParameterModel.Type}" Value="{x:Static local:DeviceModel.ParameterType.String}">
<Setter Property="ContentTemplate" Value="{StaticResource stringTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>