ListView 单元格绑定未在集合中找到方法

ListView Cell Binding not finding Methods in Collection

我正在尝试使用 MVVM and ListView for the first time. I am working from

我的 ViewModel 如下所示:

public class CodeTableViewModel : BaseViewModel
{
    public static ObservableCollection<CodeTableRow> CodeTable { get; set; }

    public CodeTableViewModel()
    {
    }

    public class CodeTableRow : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        int codePoint;

        public CodeTableRow(int point)
        {
            codePoint = point;
        }

        public string Decimal
        {
            get
            {
                return codePoint.ToString("D");
            }
        }

        public string Hex
        {
            get
            {
                return codePoint.ToString("X2");
            }
        }

        public string Ascii
        {
            get
            {
                return ((char)codePoint).ToString();
            }
        }
...

我的XAML看起来像这样

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:viewmodels="clr-namespace:RefCard.ViewModels"
             x:Class="RefCard.Views.CodeTablePage"
             Title="Code Table">
    <ContentPage.Content>
        <ListView x:DataType="viewmodels:CodeTableViewModel" ItemsSource="{Binding CodeTable}">
            <ListView.Header>
                <Grid BackgroundColor="Black">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <Label Text="Dec" HorizontalOptions="Fill"  Grid.Column="0"   FontSize="Medium" FontAttributes="Bold" BackgroundColor="MediumBlue" TextColor="White" HorizontalTextAlignment="Center" Margin="1"/>
                    <Label Text="Hex" HorizontalOptions="Fill"  Grid.Column="1"  FontSize="Medium" FontAttributes="Bold" BackgroundColor="MediumBlue" TextColor="White" HorizontalTextAlignment="Center" Margin="0"/>
                    <Label Text="ASCII" HorizontalOptions="Fill"  Grid.Column="2"  FontSize="Medium" FontAttributes="Bold" BackgroundColor="MediumBlue" TextColor="White" HorizontalTextAlignment="Center" Margin="0"/>
                </Grid>
            </ListView.Header>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid BackgroundColor="Black">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"></ColumnDefinition>
                                <ColumnDefinition Width="*"></ColumnDefinition>
                                <ColumnDefinition Width="*"></ColumnDefinition>
                            </Grid.ColumnDefinitions>
                            <Label Grid.Column="0" Text ="{Binding Decimal}" HorizontalOptions="Fill" BackgroundColor="LightBlue" HorizontalTextAlignment="Center" Margin="1" TextColor="Black"></Label>
                            <Label Grid.Column="1" Text ="{Binding Hex}" HorizontalOptions="Fill" BackgroundColor="LightBlue" HorizontalTextAlignment="Center" Margin="0"></Label>
                            <Label Grid.Column="2" Text ="{Binding Ascii}" HorizontalOptions="Fill" BackgroundColor="LightBlue" HorizontalTextAlignment="Center" Margin="0"></Label>
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ContentPage.Content>
</ContentPage>

在页面构造函数中我做了 CodeTableViewModel.CodeTable = new ObservableCollection<CodeTableViewModel.CodeTableRow>(); 和一堆添加。

我尝试破解了很多变体,但基本错误是:

XFC0045 Binding: Property "Decimal" not found on "RefCard.ViewModels.CodeTableViewModel". RefCard C:\Users\Charles\source\repos\RefCard\RefCard\Views\CodeTablePage.xaml 38

我该如何解决?

简而言之,这是您的 ListView 项的不正确的数据类型

  1. 在个人中定义您的模型class (不需要为模型 classes 实现 INotifyPropertyChanged,但在 BaseViewModel 中实现)

    namespace YourProj.Models
    {
        public class CodeTableRow
        {
            public string Decimal { get; set; }
            ...
        }
    }
    
  2. 在 CodeTableViewModel 中定义 属性 的 CodeTableRow

    public class CodeTableViewModel : BaseViewModel
    {
        public static ObservableCollection<CodeTableRow> CodeTable { get; set; }
        public CodeTableViewModel()
        {
        }
    
        private CodeTableRow _codeTableRow;
        public CodeTableRow CodeTableRow
        {
            get => _codeTableRow;
            set => SetProperty(ref _codeTableRow, value);
        }
    }
    
  3. 更正 ListView 项的数据类型

    <ContentPage
        xmlns:models="clr-namespace:YourProj.Models"
        ...>
    <ListView ...>
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="models:CodeTableRow">
            ....
    </ListView>
    

根据您的代码, 给您三点建议。

首先,你不需要添加x:DataType="viewmodels:CodeTableViewModel",因为ListView的ItemsSource="{Binding CodeTable}",然后是CodeTableRow的CodeTable列表。

其次,来自这篇文档Model-View-ViewModel Pattern

视图—视图负责定义用户在屏幕上看到的内容的结构、布局和外观。

ViewModel—视图模型实现视图可以数据绑定到的属性和命令,并通过更改通知事件通知视图任何状态更改。

模型—模型class是封装应用程序数据的非可视class模型。

所以我建议您不要在您的 ViewModel class 中添加模型 class。这是两个独立的 classes.

public class CodeTableViewModel
{
    public  ObservableCollection<CodeTableRow> CodeTable { get; set; }

    public CodeTableViewModel()
    {
        CodeTable = new ObservableCollection<CodeTableRow>();
    }
}

public class CodeTableRow : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    int codePoint;

    public CodeTableRow(int point)
    {
        codePoint = point;
    }

    public string Decimal
    {
        get
        {
            return codePoint.ToString("D");
        }
    }

    public string Hex
    {
        get
        {
            return codePoint.ToString("X2");
        }
    }

    public string Ascii
    {
        get
        {
            return ((char)codePoint).ToString();
        }
    }
 }

通常,我们在 ViewModel class 中获取一些数据,然后将 ViewModel 绑定到当前 contentPage 的 BindingContext。

public class CodeTableViewModel
{
    public  ObservableCollection<CodeTableRow> CodeTable { get; set; }

    public CodeTableViewModel()
    {
        CodeTable = new ObservableCollection<CodeTableRow>()
        {
            new CodeTableRow(12),
            new CodeTableRow(18),
            new CodeTableRow(19),
            new CodeTableRow(121),
            new CodeTableRow(124)
        };

    }
}

public Page22()
{
    InitializeComponent();

    this.BindingContext = new CodeTableViewModel();
}

如果你还想在ContentPage的构造函数中获取数据,可以看看下面的代码,但我不建议这样做。

public partial class Page22 : ContentPage, INotifyPropertyChanged
{
    private CodeTableViewModel _viewmodel;

    public CodeTableViewModel viewmodel
    {
        get { return _viewmodel; }
        set
        {
            _viewmodel = value;
            RaisePropertyChanged("viewmodel");
        }
    }

    public Page22()
    {
        InitializeComponent();
        viewmodel = new CodeTableViewModel();

        viewmodel.CodeTable = new ObservableCollection<CodeTableRow>()
        {
            new CodeTableRow(12),
            new CodeTableRow(18),
            new CodeTableRow(19),
            new CodeTableRow(121),
            new CodeTableRow(124)
        };

        this.BindingContext = viewmodel;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}