自定义ListView DataTemplate绑定/ XAML问题

时间:2016-02-10 14:15:19

标签: c# wpf xaml mvvm

我想为我的WPF MVVM(Light Toolkit)应用程序创建一个友好列表,它将从数据库生成的用户对象(在ObservableCollection或List?中)填充,并应显示如下:

enter image description here

我正在使用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);
    }
}

编辑:使用Mvvm Light从@Ilan尝试示例并调整它:

我的项目结构是这样的:

  • 模型
    • 用户
    • FriendlistSection
  • 查看
    • FriendlistView
  • 视图模型
    • FriendlistViewModel
    • MainViewModel
    • ViewModelLocator

我在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!

现在看起来像这样:

enter image description here

1 个答案:

答案 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>

  1. 您不需要GridView(您没有任何表格)。
  2. 使用ListBox而不是ItemsControl来允许选择。
  3. 设置WrapPanel宽度以查看包装是否正常工作(可选)。
  4. 我没有Tile控件,因此我使用矩形来模拟它。
  5. 请注意Grid(名为&#34; LayoutRoot&#34;)为ListView提供DataContext(名为&#34; ItemsPresentingListView&#34;)。
  6. 以下是修改过的视图模型(请考虑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();
            }
        }
    }
    

    看起来如何: here

    问候。