我想为我的WPF MVVM(Light Toolkit)应用程序创建一个友好列表,它将从数据库生成的用户对象(在ObservableCollection或List?中)填充,并应显示如下:
我正在使用MahApps Metro,并会在每个字母字母的WrapPanel中使用Tiles。但现在我无法弄清楚我是如何为ListView正确构建DataTemplate的。
因此,如果我的代码完全错误,我怎样才能在XAML中使用DataBindings正确创建View(如上图所示),如示例代码中所示? GridView会更好吗?
我的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; }
}
我的MainViewModel用测试数据显示它:
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);
}
}
我的项目结构是这样的:
我在FriendlistView中创建了ListView:
<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); }
}
}
用户:
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>();
现在它工作正常,添加了IgnoreMouseWheelBehaivior,因为它由ScrollViewer处理并将WrapPanel Width从Grid中设置为通过MainWindow中的ScrollViewer调整大小。
再次感谢@Ilan!
现在看起来像这样:
答案 0 :(得分:1)
请尝试下一个:
Xaml代码:
<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>
以下是修改过的视图模型(请考虑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();
}
}
}
问候。