XAML 绑定到对象时ListView不工作

cclgggtu  于 2023-06-19  发布在  其他
关注(0)|答案(1)|浏览(163)

如果对象只是一个字符串,我可以正常绑定ItemsSource,但当它是一个记录或类时,应用程序将无法启动。过了一会儿,我得到了这个错误:
System.InvalidCastException:指定的强制转换无效
下面是我的XAML标记:

<ListView x:Name="Posts">
    <ListView.ItemTemplate>
        <DataTemplate>
            <VerticalStackLayout Spacing="25" Margin="10,0" VerticalOptions="Center">
                <Frame BackgroundColor="#191919">
                    <VerticalStackLayout>
                        <VerticalStackLayout Margin="5">
                            <Label Text="{Binding Name}" FontSize="18" TextColor="Gray" />
                            <Label Text="{Binding Title}" FontSize="Large" FontAttributes="Bold" />
                        </VerticalStackLayout>
                        <Border>
                            <Border.StrokeShape>
                                <RoundRectangle CornerRadius="5" />
                            </Border.StrokeShape>
                            <Image MinimumHeightRequest="200" MaximumHeightRequest="350" Aspect="AspectFill" Source="{Binding Image}" />
                        </Border>
                        <HorizontalStackLayout Margin="0,5,0,0">
                            <Button ImageSource="upvote.png" BackgroundColor="Transparent" />
                            <Label Text="{Binding Votes}" FontSize="Medium" Margin="0, 10, 0, 0" TextColor="Gray" />
                            <Button ImageSource="downvote.png" BackgroundColor="Transparent" />
                        </HorizontalStackLayout>
                    </VerticalStackLayout>
                </Frame>
            </VerticalStackLayout>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

下面是绑定代码:

List<Data> items = new() { new Data("User", "Lorem ipsum dolor sit amet", "21", "<Image url>") };
Posts.ItemsSource = items;

我做错了什么?

62lalag4

62lalag41#

是的,你需要在你的<DataTemplate>中添加<ViewCell>,代码如下:

<ListView x:Name="mListView" HasUnevenRows="True">
    <ListView.ItemTemplate>
        <DataTemplate>
              <!-- add  ViewCell  here  -->
            <ViewCell>
              <VerticalStackLayout Spacing="25" Margin="10,0" VerticalOptions="Center" >
                <Frame BackgroundColor="Yellow">
                    <!--  other code -->
                </Frame>
            </VerticalStackLayout>
            </ViewCell>
            
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

我发现你在项目中添加了两个按钮(upvotedownvote),所以我强烈建议你使用MVVM模式。然后你可以将ICommand添加到页面的ViewModel中,并将其绑定到按钮。
此外,如果您想在更改绑定属性的值时更新UI(例如Votes),您可以为ViewModel实现接口INotifyPropertyChanged,并为属性调用事件OnPropertyChanged
本人创建了一个demo并实现了此功能,可以参考以下代码:
1.为Data.cs实现INotifyPropertyChanged并添加属性Votes,如下所示:

private int _votes;
    public int Votes
    {
        set { SetProperty(ref _votes, value); }
        get { return _votes; }
    }

Data.cs

public class Data: INotifyPropertyChanged 
{
    public Data(string v1, string v2, int v3, string v4)
    {
        this.Name = v1;
        this.Title = v2;
        this.Votes = v3;
        this.Image = v4;
    }

    public string Name { get; set; }
    public string Title { get; set; }
    //public string Votes { get; set; }

    private int _votes;
    public int Votes
    {
        set { SetProperty(ref _votes, value); }
        get { return _votes; }
    }

    public string Image { get; set; }
    bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Object.Equals(storage, value))
            return false;
        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

2.为页面创建视图模型(MyViewModel.cs)

public class MyViewModel 
{
    public List<Data> Items { get; set; }

    public ICommand UpVoteCommand { get; set; }
    public ICommand DownVoteCommand { get; set; }

    public MyViewModel() {

        Items = new List<Data>();

        Items.Add(new Data("User1", "Lorem ipsum dolor sit amet1", 21, "<Image url>"));
        Items.Add(new Data("User2", "Lorem ipsum dolor sit amet2", 22, "<Image url>"));
        Items.Add(new Data("User3", "Lorem ipsum dolor sit amet3", 23   , "<Image url>"));

        UpVoteCommand = new Command((object item) => {
            if (item != null && item is Data)
            {
                Data data = (Data)item;
                data.Votes++;

            }
        });

        DownVoteCommand = new Command((object item) => {
            if (item != null && item is Data)
            {
                Data data = (Data)item;
                data.Votes--;

            }
        });

    }
}

3.使用示例:

主页.xaml

<?xml version="1.0" encoding="utf-8" ?> 
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp618.MainPage">

    <ListView x:Name="mListView" HasUnevenRows="True" ItemsSource="{Binding Items}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                  <VerticalStackLayout Spacing="25" Margin="10,0" VerticalOptions="Center" >
                    <Frame BackgroundColor="Yellow">
                        <VerticalStackLayout>
                            <VerticalStackLayout Margin="5">
                                <Label Text="{Binding Name}" FontSize="18" TextColor="Gray" />
                                <Label Text="{Binding Title}" FontSize="Large" FontAttributes="Bold" />
                            </VerticalStackLayout>
                            <Border>
                                <Border.StrokeShape>
                                    <RoundRectangle CornerRadius="5" />
                                </Border.StrokeShape>
                                <Image MinimumHeightRequest="100" MaximumHeightRequest="100" Aspect="AspectFill" Source="{Binding Image}" />
                            </Border>
                            <HorizontalStackLayout Margin="0,5,0,0">
                                 <Button ImageSource="upvote.png" WidthRequest="60"  HeightRequest="60" BackgroundColor="Transparent" 
                                         Command="{Binding Source={x:Reference mListView}, Path=BindingContext.UpVoteCommand}"
                                         CommandParameter="{Binding .}"
                                         />
                                <Label Text="{Binding Votes}" FontSize="Medium" Margin="0, 10, 0, 0" TextColor="Gray" />
                                <Button ImageSource="downvote.png"  WidthRequest="60"  HeightRequest="60" BackgroundColor="Transparent" 
                                        Command="{Binding Source={x:Reference mListView}, Path=BindingContext.DownVoteCommand}"
                                        CommandParameter="{Binding .}"
                                        
                                        />
                            </HorizontalStackLayout>
                        </VerticalStackLayout>
                    </Frame>
                </VerticalStackLayout>
                </ViewCell>
                
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

</ContentPage>

MainPage.xaml.cs

public partial class MainPage : ContentPage 
{
      public MainPage()
      {
            InitializeComponent();

        //List<Data> items = new() { new Data("User", "Lorem ipsum dolor sit amet", "21", "<Image url>") };
        //mListView.ItemsSource = items;

        this.BindingContext= new MyViewModel();
    }
}

相关问题