I wanted to create a friendlist for my WPF MVVM (Light Toolkit) Application, which will get filled from database generated User Objects (in ObservableCollection or List?) and should be displayed as following:
I'm using MahApps Metro and would use Tiles in a WrapPanel for each alphabetic Letter. But now I can't figure out how I correctly build the DataTemplate for the ListView.
So if my Code is totally wrong, how could I correctly create the View (from image above) in XAML with DataBindings as you can see in the example code? Would be a GridView better?
My XAML (FriendlistView):
<UserControl
<!-- Stuff -->
DataContext="{Binding Friendlist, Source={StaticResource Locator}}">
<Grid Background="White">
<ListView ItemsSource="{Binding Path=FriendsCompleteList}">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Path=Friends}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=Letter}"/>
<WrapPanel Orientation="Horizontal"/>
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<controls:Tile Title="{Binding Path=Username}"
TiltFactor="2"
Height="100" Width="100">
<Image Height="40" Width="40"/>
</controls:Tile>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<!-- Just Closing Tags -->
My FriendlistViewModel as DataContext:
public class FriendlistViewModel : ViewModelBase
{
private List<FriendlistPart> _friendsCompleteList;
public FriendlistViewModel(List<FriendlistPart> friendsCompleteList)
{
FriendsCompleteList = friendsCompleteList;
}
public List<FriendlistPart> FriendsCompleteList
{
get { return _friendsCompleteList; }
set { Set(ref _friendsCompleteList, value); }
}
}
public class FriendlistPart
{
public string Letter { get; set; }
public IList<User> Friends { get; set; }
}
And my MainViewModel to Display it with Test Data:
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
var userList= new List<User>{
new User { Username = "test" },
new User { Username = "test1" },
new User { Username = "test2" }
};
var friendlistCompleteList= new List<FriendlistPart>
{
new FriendlistPart { Friends = userList, Letter = "A" },
new FriendlistPart { Friends = userList, Letter = "B" },
new FriendlistPart { Friends = userList, Letter = "C" }
};
CurrentPageViewModel = new FriendlistViewModel(friendlistCompleteList);
}
}
My projectstructure is like this:
I created the ListView in FriendlistView:
<UserControl x:Class="Messenger4u.View.FriendlistView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:model="clr-namespace:Messenger4u.Model"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:messenger4U="clr-namespace:Messenger4u"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
DataContext="{Binding Main, Source={StaticResource Locator}}">
<Grid x:Name="LayoutRoot" DataContext="{Binding CurrentPageViewModel}">
<ListView x:Name="ItemsPresentingListView" Margin="0, -5, 0, 0" BorderThickness="0" ItemsSource="{Binding Path=FriendlistComplete}" >
<i:Interaction.Behaviors>
<messenger4U:IgnoreMouseWheelBehavior />
</i:Interaction.Behaviors>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type model:FriendlistSection}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Margin="0, 5, 0, 5" Text="{Binding Path=Letter}" FontSize="15"/>
<Rectangle Grid.Row="0" VerticalAlignment="Bottom" Fill="Black" Height="1" HorizontalAlignment="Stretch"/>
<ListBox Grid.Row="1" Margin="-2, 0, 0, 0" ItemsSource="{Binding Friends}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" Width="{Binding ActualWidth, ElementName=LayoutRoot}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<controls:Tile Title="{Binding Username}"
TiltFactor="2"
Height="100" Width="100"
Margin="8, 15, 15, 15"
Background="DodgerBlue">
<Image Height="40" Width="40" Source="../Skins/Images/user.jpg"/>
</controls:Tile>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
FriendlistViewModel:
public class FriendlistViewModel : ViewModelBase
{
private ObservableCollection<FriendlistSection> _friendlistComplete;
public FriendlistViewModel(List<FriendlistSection> friendlist)
{
FriendlistComplete = new ObservableCollection<FriendlistSection>(friendlist);
}
public ObservableCollection<FriendlistSection> FriendlistComplete
{
get { return _friendlistComplete; }
set { Set(ref _friendlistComplete, value); }
}
}
FriendlistSection:
public class FriendlistSection : ObservableObject
{
private string _letter;
private ObservableCollection<User> _friends;
public string Letter
{
get { return _letter; }
set { Set(ref _letter, value); }
}
public ObservableCollection<User> Friends
{
get { return _friends; }
set { Set(ref _friends, value); }
}
}
User:
public class User : ObservableObject
{
private string _username;
public string Username
{
get { return _username; }
set { Set(ref _username, value); }
}
MainViewModel:
public MainViewModel()
{
var userList = new ObservableCollection<User>
{
new User {Username = "test"},
new User {Username = "test1"},
new User {Username = "test2"}
};
var userList1 = new ObservableCollection<User>
{
new User {Username = "test3"},
new User {Username = "test4"},
new User {Username = "test2"},
new User {Username = "test5"},
new User {Username = "test6"},
new User {Username = "test7"},
new User {Username = "test8"},
};
var userList2 = new ObservableCollection<User>
{
new User {Username = "test9"},
new User {Username = "test10"},
};
var friendlistCompleteList = new List<FriendlistSection>
{
new FriendlistSection {Friends = userList, Letter = "A"},
new FriendlistSection {Friends = userList1, Letter = "B"},
new FriendlistSection {Friends = userList2, Letter = "C"}
};
// Can use var, but here was my mistake to create the
// FriendlistViewModel as ViewModelBase
FriendlistViewModel friendlistViewModel = new FriendlistViewModel(friendlistCompleteList);
CurrentPageViewModel = friendlistViewModel ;
}
// Bound to ContentControl in MainWindow
public ViewModelBase CurrentPageViewModel
{
get { return _currentPageViewModel; }
set { Set(ref _currentPageViewModel, value); }
}
ViewModelLocator:
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<User>();
SimpleIoc.Default.Register<FriendlistSection>();
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<FriendlistViewModel>();
}
public MainViewModel Main => ServiceLocator.Current.GetInstance<MainViewModel>();
public FriendlistViewModel Friendlist => ServiceLocator.Current.GetInstance<FriendlistViewModel>();
Now it works fine, added the IgnoreMouseWheelBehaivior, because it gets handled by a ScrollViewer and set the WrapPanel Width to ActualWidth from the Grid that gets sized trough the ScrollViewer in MainWindow.
Thanks again to @Ilan!
Now it looks like this:
please try the next:
Xaml code:
<Window x:Class="ListViewDataTemplateContainingListViewAndMore.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:listViewDataTemplateContainingListViewAndMore="clr-namespace:ListViewDataTemplateContainingListViewAndMore"
Title="MainWindow" Height="350" Width="525" x:Name="This">
<Window.DataContext>
<listViewDataTemplateContainingListViewAndMore:MainViewModel/>
</Window.DataContext>
<Grid x:Name="LayoutRoot" DataContext="{Binding CurrentPageViewModel}">
<ListView x:Name="ItemsPresentingListView" ItemsSource="{Binding Path=FriendsCompleteList}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type listViewDataTemplateContainingListViewAndMore:FriendlistPart}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition ></RowDefinition>
<RowDefinition ></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Path=Letter}" FontWeight="Bold" FontSize="15"/>
<Rectangle Grid.Row="0" VerticalAlignment="Bottom" Fill="Black" Height="3" HorizontalAlignment="Stretch"></Rectangle>
<ListBox Grid.Row="1" ItemsSource="{Binding Friends}" BorderBrush="#00FFFFFF">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" Width="500"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Grid>
<Rectangle Width="120" Height="120" Fill="Blue"></Rectangle>
<Ellipse Width="90" Height="90" Fill="Tomato"></Ellipse>
</Grid>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
<Run Text="Name: "></Run>
<Run Text="{Binding Username}"></Run>
</TextBlock>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox></Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
Here are a modified view models (please take in account the next article )
public class FriendlistViewModel : BaseObservableObject
{
private ObservableCollection<FriendlistPart> _friendsCompleteList;
public FriendlistViewModel(List<FriendlistPart> friendsCompleteList)
{
FriendsCompleteList = new ObservableCollection<FriendlistPart>(friendsCompleteList);
}
public ObservableCollection<FriendlistPart> FriendsCompleteList
{
get { return _friendsCompleteList; }
set { Set(ref _friendsCompleteList, value); }
}
}
public class FriendlistPart:BaseObservableObject
{
private string _letter;
private ObservableCollection<User> _friends;
public string Letter
{
get { return _letter; }
set
{
_letter = value;
OnPropertyChanged();
}
}
public ObservableCollection<User> Friends
{
get { return _friends; }
set
{
_friends = value;
OnPropertyChanged();
}
}
}
public class User:BaseObservableObject
{
private string _username;
public string Username
{
get { return _username; }
set
{
_username = value;
OnPropertyChanged();
}
}
}
public class MainViewModel : BaseObservableObject
{
private FriendlistViewModel _currentPageViewModel;
public MainViewModel()
{
var userList = new ObservableCollection<User>
{
new User {Username = "test"},
new User {Username = "test1"},
new User {Username = "test2"}
};
var userList1 = new ObservableCollection<User>
{
new User {Username = "test3"},
new User {Username = "test4"},
new User {Username = "test2"},
new User {Username = "test5"},
new User {Username = "test6"},
new User {Username = "test7"},
new User {Username = "test8"},
};
var userList2 = new ObservableCollection<User>
{
new User {Username = "test9"},
new User {Username = "test10"},
};
var friendlistCompleteList = new List<FriendlistPart>
{
new FriendlistPart {Friends = userList, Letter = "A"},
new FriendlistPart {Friends = userList1, Letter = "B"},
new FriendlistPart {Friends = userList2, Letter = "C"}
};
CurrentPageViewModel = new FriendlistViewModel(friendlistCompleteList);
}
public FriendlistViewModel CurrentPageViewModel
{
get { return _currentPageViewModel; }
set
{
_currentPageViewModel = value;
OnPropertyChanged();
}
}
}
Regards.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.