没有DataBinding的UWP ListView

时间:2016-07-27 12:49:11

标签: listview data-binding uwp windows-10-universal uwp-xaml

我刚刚开始使用UWP,我正在尝试使用项目创建ListView。 我已经看过一些教程,但所有教程都使用DataBinding。

有没有办法在没有DataBinding的情况下创建ListView? DataBinding对于简单模型来说非常棒,但是当它变得复杂时我更喜欢自己填充视图。就像从网址加载图片,从日期到字符串和那些东西。

这可能吗? (如果我完全看错了,请纠正我)

修改

这就是我在Android上填写列表的方式:

  • 我有一个项目列表(例如具有firstName和lastName的Person)。
  • 我有一个列表项的布局(例如只是一个textBlock)
  • 我有一个ViewHolder,它在单个列表项中保存对视图的引用(例如textBlock)。这个ViewHolder可以重复使用。
  • 我有一个适配器,它将信息提供给ListView(如项目数和创建ViewHolders并将数据绑定到ViewHolder)
  • 将数据绑定到ViewHolder时,我可以充分灵活地使用它。我引用了列表项中的每个View。所以例如我可以用firstName和lastName组合填充textBlock(这都是在代码而不是布局文件中完成的)

3 个答案:

答案 0 :(得分:2)

所以请允许我在前面加上这一点,你对数据绑定大错100%...事情越复杂,DataBinding就越有用。事实上,事实恰恰相反。人们倾向于发现MVVM进程和数据绑定对于简单的示例来说有点健壮。

那说......

以下是您要问的问题。

要将商品添加到列表视图中,您只需拨打Items.Add

即可

在我的Xaml中,我有ListView名为TestListview

<Grid>
    <ListView x:Name="TestListview"/>
</Grid>

在我的后台代码(Xaml.cs)中,我在构造函数中有以下内容。

TestListview.Items.Add("Item One");
TestListview.Items.Add("Item Two");
TestListview.Items.Add("Item Three"); 

那就是它。现在,项目将在我的列表视图中。再一次,这是做到这一点的最糟糕的方式,不可维护,是一个不好的学习实践,会让你受到惩罚,皮重和羽毛作为一个专业人士。

祝你好运!

更新

根据OP的要求,这里有一个例子,说明为什么没有数据绑定生活是可怕的

我们将探讨两个例子。在我们的第一个示例中,我们将研究如何使用具有一些属性的对象填充列表视图。然后,我们将在单击该对象时启用该对象的详细视图。

然后在我们的第二个例子中,我们将看到如何仅使用数据绑定来完成同样的事情。

对于这两个例子,我将使用这个虚拟数据生成器和模型

   public static IEnumerable<PersonModel> GenerateFakePeople()
   {
            List<PersonModel> people = new List<PersonModel>();
            people.Add(new PersonModel() { FirstName = "Aaron", LastName = "Doe", Age = 11, Bio = "This is a short bio bio bio blah blah blah.", ImageURL= "http://media.boingboing.net/wp-content/uploads/2012/02/breadingcats.jpg" });
            people.Add(new PersonModel() { FirstName = "John", LastName = "Doe", Age = 21, Bio = "This is a short bio bio bio blah blah blah.", ImageURL = "http://media.boingboing.net/wp-content/uploads/2012/02/breadingcats.jpg" });
            people.Add(new PersonModel() { FirstName = "David", LastName = "Doe", Age = 31, Bio = "This is a short bio bio bio blah blah blah.", ImageURL = "http://media.boingboing.net/wp-content/uploads/2012/02/breadingcats.jpg" });
            return people;
    }

    public class PersonModel
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }
        public string ImageURL { get; set; }
        public string Bio { get; set; }
    }

正如您在xaml中看到的那样,我已经将其扩展为包含一个显示我们已被点击的用户的地方。

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width=".3*"/>
        <ColumnDefinition Width=".7*"/>
    </Grid.ColumnDefinitions>
    <ListView x:Name="TestListview" Grid.Column="0" SelectionChanged="TestListview_SelectionChanged"/>
    <Grid Grid.Column="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width=".3*"/>
            <ColumnDefinition Width=".7*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="200"/>
            <RowDefinition Height="300"/>
        </Grid.RowDefinitions>
        <Image x:Name="PersonsImage" Grid.Column="0" Grid.Row="0"/>
        <StackPanel Orientation="Vertical" Grid.Column="1" Grid.Row="0">
            <TextBlock x:Name="PersonsName" FontSize="25"/>
            <TextBlock x:Name="PersonsAge" FontSize="25"/>
        </StackPanel>
        <TextBlock x:Name="PersonsBio" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" FontSize="30" TextWrapping="Wrap"/>
    </Grid>
</Grid>

在我们的后面的代码中,您可以看到信息不仅仅填充在屏幕上,而且还有用于创建每个UI项目的高度耦合的工作。

当我们像这样将UI元素紧密地结合在一起时,很难在不破坏事物的情况下更改UI。不仅如此,它也很难改变模型。

例如,如果我想更改我的PersonModel对象以支持全名而不是第一个和最后一个,我将不得不通过并更改具有引用的第一个名称属性的每一行代码。

更糟糕的是,如果我添加一个全名属性但决定保留名字和姓氏属性,但想要将它们切换出来,我将不得不手动检查所有引用该名称的点。旧的财产。

哦,我如何访问生物?我们正在从ListView捕获选择更改事件,但我们只能从UI元素访问数据,因为我们从未真正将PersonModel绑定到ListViewItem。

最后,更新屏幕,这可能是数据绑定的最大卖点。如果出于某种原因我在代码中修改某人的姓名,我会改变他们的年龄,他们的生物或附加到他们的其他财产会发生什么?我必须通过UI并手动更新引用属性的每个位置。这意味着我必须跟踪它所引用的每个地方。这是高度耦合和非常差的设计。

 public partial class MainWindow : Window
    {

    public MainWindow()
    {            
        InitializeComponent();

        foreach(PersonModel person in GenerateFakePeople())
        {
            TestListview.Items.Add(GenerateItem(person));
        }
    }


    public static StackPanel GenerateItem(PersonModel person)
    {
        StackPanel outerStackPanel = new StackPanel() { Orientation = Orientation.Horizontal };
        StackPanel innerStackPanel = new StackPanel() { Orientation = Orientation.Vertical };
        Image image = new Image() { Source = new BitmapImage(new Uri(person.ImageURL)) };
        TextBlock firstName = new TextBlock() { Text = person.FirstName };
        TextBlock lastName = new TextBlock() { Text = person.LastName };
        TextBlock age = new TextBlock() { Text = person.Age.ToString() };
        TextBlock bio = new TextBlock() { Text = person.Bio };

        outerStackPanel.Children.Add(image);
        outerStackPanel.Children.Add(innerStackPanel);
        innerStackPanel.Children.Add(firstName);
        innerStackPanel.Children.Add(lastName);
        innerStackPanel.Children.Add(age);

        return outerStackPanel;
    }

    private void TestListview_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        StackPanel outerStackPanel = (sender as ListView).SelectedItem as StackPanel;

        if (outerStackPanel != null)
        {
            Image image = outerStackPanel.Children[0] as Image;
            StackPanel innerStackPanel = outerStackPanel.Children[1] as StackPanel;

            if (innerStackPanel != null)
            {
                TextBlock firstName = innerStackPanel.Children[0] as TextBlock;
                TextBlock lastName = innerStackPanel.Children[1] as TextBlock;
                TextBlock age = innerStackPanel.Children[2] as TextBlock;
               // TextBlock bio = innerStackPanel.Children[3] as TextBlock;

                PersonsImage.Source = image.Source;
                PersonsName.Text = firstName.Text + " " + lastName.Text;
                PersonsAge.Text = age.Text;
             //   PersonsBio.Text = bio.Text; //Cant Even access the bio! It doesn't exist!
            }
        }
    }
}  

现在让我们看一下数据绑定示例。

使用DataBinding,我们可以简化后面的代码。它允许我们使用MVVM之类的模式。在大规模工作时,这是非常强大的。

这是我们新的Xaml文件

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width=".3*"/>
            <ColumnDefinition Width=".7*"/>
        </Grid.ColumnDefinitions>
        <ListView x:Name="PeopleListView" Grid.Column="0" ItemsSource="{Binding People}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding ImageURL}" Height="100" Width="100"/>
                        <StackPanel Orientation="Vertical">
                            <TextBlock Text="{Binding FirstName}" />
                            <TextBlock Text="{Binding LastName}" />
                            <TextBlock Text="{Binding Age}" />
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <Grid Grid.Column="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width=".3*"/>
                <ColumnDefinition Width=".7*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="200"/>
                <RowDefinition Height="300"/>
            </Grid.RowDefinitions>
            <Image Source="{Binding ElementName=PeopleListView, Path=SelectedItem.ImageURL}"  Grid.Column="0" Grid.Row="0"/>
            <StackPanel Orientation="Vertical" Grid.Column="1" Grid.Row="0">
                <TextBlock Text="{Binding ElementName=PeopleListView, Path=SelectedItem.FirstName}"  FontSize="25"/>
                <TextBlock Text="{Binding ElementName=PeopleListView, Path=SelectedItem.Age}" FontSize="25"/>
            </StackPanel>
            <TextBlock Text="{Binding ElementName=PeopleListView, Path=SelectedItem.Bio}" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" FontSize="30" TextWrapping="Wrap"/>
        </Grid>
    </Grid>

正如你所看到的,有些事情发生了变化。您应该注意的第一件事是ListView现在有一个ItemTemplate。这表示对于添加到ListView的每个项目,这是您希望它在控件中显示的方式。这允许我们将所有UI设计内容保存在它所属的xaml中。

您应该注意的第二件事是我现在将我的人物显示区域绑定到ListView的SelectedItem属性。这允许我们直接访问实际的数据对象,而不必挖掘控件。这是处理数据的一种更优越的方法。

最后让我们来看看我们的CS

    private ObservableCollection<PersonModel> _people;

    public ObservableCollection<PersonModel> People
    {
        get { return _people; }
        set { _people = value; }
    }


    public MainWindow()
    {            
        InitializeComponent();
        People = new ObservableCollection<PersonModel>(GenerateFakePeople());
        this.DataContext = this;
    }

如您所见,我们的CS大大简化了。不仅如此,我们还可以对我们的对象进行操作,并且可以通过触发PropertyChangedEvent来保持UI的同步。这将更新绑定到属性的所有内容。我们还可以轻松地将更多PersonModel添加到People集合中,它也会反映在屏幕上。

我理解您对DataBinding和MVVM架构的理解。我向你保证,尽管整个社区都没有错。我们正在积累数十年的不良做法。 MVVM为企业提供了一种非常模块化且经济高效的软件构建方式。它允许您轻松地重用代码,最重要的是,如果出现问题,很容易找到,因为您不需要搜索代码以查找对属性的百万个引用。你只需修复一次。

我强烈建议您对MVVM,DataBinding和面向对象编程进行一些研究。走出去,实际构建一些您需要维护的手机应用程序或软件。然后,当您因为更改了某些内容的文本而需要花费一个小时来更新代码时,您将会理解。

以下是我要研究的一些资源。如果他们说WPF而不是UWP,请不要害怕。对于这些主题,模式几乎相同。

What is MVVM?

What is DataBinding?

Creating User Controls

Creating Lookless Controls

答案 1 :(得分:0)

在我看来,当你不想使用数据绑定时,确实没有那么多的情况。在引入x:Bind之前,性能损失并不像以前那么大。除此之外,您可以执行使用转换器提及的日期格式等操作。

如果我有一个可以在很多方面呈现的非常复杂的项目,我使用UserControl。我只是将数据对象绑定到UserControl上的属性,并处理此UserControl的代码隐藏中的所有内容。

答案 2 :(得分:0)

在我看来,你完全错了! : - )

创建List的实例,其中MyItem是您想要手动添加到ListView的同一个类(与您添加到ListView的Items属性相同)。最后你有一个包含很多对象的List。

然后你可以简单地说:

this.listView1.ItemsSource = your_instance_of_list

完成!之后,您需要设置一个ItemTemplate。