无法将ListView绑定到ViewModel

时间:2018-04-09 23:31:50

标签: xamarin data-binding xamarin.forms

这是我的ViewModel:

namespace DietAndFitness.ViewModels
{
public class FoodItemsViewModel 
{
    private SQLiteAsyncConnection database;

    public static ObservableCollection<GlobalFoodItem> FoodItems { get; set; }

    public FoodItemsViewModel(SQLiteAsyncConnection _database)
    {
        database = _database;        
    }

    public async void LoadList()
    {
         FoodItems = new ObservableCollection<GlobalFoodItem>(await database.Table<GlobalFoodItem>().ToListAsync());
    }
    public void Add()
    {
        FoodItems.Add(new GlobalFoodItem("Item"));
    }
}
}

我想将此VM的实例绑定到我的视图中的列表,但我无法让它正常工作。我唯一能够成功的是:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:local="clr-namespace:DietAndFitness.ViewModels"
         x:Class="DietAndFitness.Views.FoodDatabasePage">
<ContentPage.Content>
    <StackLayout>
        <ListView ItemsSource="{Binding FoodItems}" RowHeight="120">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <ContentView Padding="5">
                            <Frame OutlineColor="Accent" Padding="10">
                                <StackLayout>
                                    <Grid HorizontalOptions="Center">
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto"/>
                                        </Grid.RowDefinitions>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto"/>
                                            <ColumnDefinition Width="Auto" />
                                        </Grid.ColumnDefinitions>
                                        <Label Text="{Binding Name}" FontSize="22" VerticalOptions="CenterAndExpand" HorizontalOptions="Center" Grid.Row="0" Grid.Column="0"/>
                                        <Label Text="{Binding Calories}" FontSize="22" VerticalOptions="CenterAndExpand" HorizontalOptions="Center" Grid.Row="0" Grid.Column="1"/>
                                    </Grid>

                                    <Grid HorizontalOptions="Center">
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto"/>
                                            <RowDefinition Height="Auto"/>
                                        </Grid.RowDefinitions>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto"/>
                                            <ColumnDefinition Width="Auto" />
                                            <ColumnDefinition Width="Auto" />
                                        </Grid.ColumnDefinitions>

                                        <Label Text="Carbohydrates" Grid.Row="1" Grid.Column="0" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" FontSize="16"/>
                                        <Label Text="Proteins" Grid.Row="1" Grid.Column="1" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" FontSize="16"/>
                                        <Label Text="Fats" Grid.Row="1" Grid.Column="2" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" FontSize="16"/>

                                        <Label Text="{Binding Carbohydrates}" Grid.Row="2" Grid.Column="0" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" FontSize="16"/>
                                        <Label Text="{Binding Proteins}" Grid.Row="2" Grid.Column="1" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" FontSize="16"/>
                                        <Label Text="{Binding Fats}" Grid.Row="2" Grid.Column="2" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" FontSize="16"/>
                                    </Grid>
                                </StackLayout>
                            </Frame>
                        </ContentView>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <Grid HorizontalOptions="Center">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Button x:Name="AddFoodItemButton" BackgroundColor="LightGray" HorizontalOptions="CenterAndExpand" Text="Add" Grid.Row="0" Grid.Column="0" Clicked="AddFoodItemButton_Clicked" />
            <Button x:Name="EditFoodItemButton" BackgroundColor="LightGray" HorizontalOptions="CenterAndExpand" Text="Edit" Grid.Row="0" Grid.Column="1" />
            <Button x:Name="DeleteFoodItemButton" BackgroundColor="LightGray" HorizontalOptions="CenterAndExpand" Text="Delete" Grid.Row="0" Grid.Column="2"  />
        </Grid>
    </StackLayout>
</ContentPage.Content>

但这也存在问题:

  1. 如果我在页面构造函数中创建VM,则列表不会加载,除非我刷新页面
  2. 如果我在App.cs中创建VM,列表将在第一次尝试时加载,但我似乎无法访问VM的实例
  3. 如何将ListView绑定到此VM?是否可以在不使我的ObservableCollection静态的情况下这样做? 我在我的应用程序中使用了Master-Detail页面,如果它有任何区别(这是其中一个详细页面)。

    编辑:这是我在构造函数中所做的。 SQLiteConnection.Database只是一个包含与数据库连接的静态类。

        public FoodDatabasePage ()
        {
            FoodDatabase = new FoodItemsViewModel(SQLiteConnection.Database);
            FoodDatabase.LoadList();
            InitializeComponent ();
        }
    

1 个答案:

答案 0 :(得分:0)

你有一些事情。

当绑定ViewModel时,它通常与整个Page相对应,使ViewModel成为BindingContext,特别是在您拥有想要稍后访问的方法的情况下。

所以要做到这一点,你需要做一些改变。

您的网页XAML

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:local="clr-namespace:DietAndFitness.ViewModels"
        x:Class="DietAndFitness.Views.FoodDatabasePage">
<ContentPage.Content>
    <StackLayout>
        <ListView ItemsSource="{Binding FoodItems}" 
                RowHeight="120">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Frame OutlineColor="Accent" Padding="15">
                            <StackLayout>
                                <Grid HorizontalOptions="Center">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto"/>
                                    </Grid.RowDefinitions>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto"/>
                                        <ColumnDefinition Width="Auto" />
                                    </Grid.ColumnDefinitions>
                                    <Label Text="{Binding Name}" 
                                        FontSize="22" 
                                        VerticalOptions="CenterAndExpand" 
                                        HorizontalOptions="Center" 
                                        Grid.Row="0" 
                                        Grid.Column="0"/>
                                </Grid>
                            </StackLayout>
                        </Frame>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

检查我ListView中是否更改了ItemSource FoodItemsViewModel作为集合名称。

此外,你的部分XAML消失了,所以我无法完成它。

您的代码在课程背后:(FoodDatabasePage.xaml.cs)

public FoodItemsViewModel FoodDatabase {get; set;}

public FoodDatabasePage ()
{
    InitializeComponent ();
    FoodDatabase = new FoodItemsViewModel(SQLiteConnection.Database);
    BindingContext = FoodDatabase;
}

public override void OnAppearing()
{
    FoodDatabase.LoadList();    
}

这是“神奇”发生的地方。我们正在创建和存储FoodItemsViewModel的对象,以便您可以在以后根据需要访问它,然后我们将最近创建的此对象设置为页面的BindingContext(如上所述)。将ViewModel设置为Page的BindingContext,后者将能够访问FoodItemsViewModel的任何公共属性。

另外,您会注意到LoadList()方法已从构造函数中删除,这是因为Page构造函数中不应存在任何繁重的事务(实际上我们应该避免任何事务)。我们将其移动到OnAppearing将要显示的Page执行的namespace DietAndFitness.ViewModels { public class FoodItemsViewModel { private SQLiteAsyncConnection database; //You don't need it static public ObservableCollection<GlobalFoodItem> FoodItems { get; set; } public FoodItemsViewModel(SQLiteAsyncConnection _database) { database = _database; } public async void LoadList() { // separated it only for readability. var items = await database.Table<GlobalFoodItem>().ToListAsync(); FoodItems = new ObservableCollection<GlobalFoodItem>(items); } public void Add() { FoodItems.Add(new GlobalFoodItem("Item")); } } } 回调方法。

注意:每次在屏幕上显示页面时都会调用此方法,因此如果您离开并返回,它将再次被调用。

您的ViewModel:

static

这几乎是一样的。唯一的变化是将FoodItems限定符移除到INotifiedPropertyChanged属性,因为它不再需要它了。

以上只是Mvvm和DataBinding的基础。还需要考虑其他一些事项,例如Commandgw.cloud.config.json和其他重要事项。

您可以找到有关此here

的更多信息

希望这会有所帮助.-

PS:我无法检查您的所有代码是否有任何错误。

相关问题