【问题标题】:Xamarin.Forms, XAML, Bindings and isVisibleXamarin.Forms、XAML、绑定和 isVisible
【发布时间】:2018-08-31 21:26:49
【问题描述】:

我(显然,关于这个问题)是新手,所以提前感谢您的帮助!由于我现在正在尽我最大的努力,我希望有人可以加快我的学习曲线:)

附录:我也在 Xamarin 论坛上发帖,但是对于问题答案的数量,这似乎是相当死板的。因此,我希望没有人冒犯。

所以,我有我的 XAML 主页:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="cant post links"
             xmlns:x="cant post links"
             xmlns:local="clr-namespace:App.ViewModels"
             x:Class="App.ViewModels.MainPage">

    <ContentPage.BindingContext>
        <local:User/>
    </ContentPage.BindingContext>

    <StackLayout>
        <Label Text="Test"/>
        <ListView ItemsSource="{Binding Changes}"
                  x:Name="ChangesList"
                  HasUnevenRows="True"
                  Margin="40,80"
                  ItemTapped="ListView_ItemTapped">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout>
                            <Label Text="{Binding Name}"/>
                            <Button Text="Details"
                                    IsVisible="{Binding IsVisible}"/>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <Button Text="Press to add" x:Name="addItem" Clicked="addItem_Clicked"/>
    </StackLayout>

</ContentPage>

我有一个带有相应属性的数据模型。当我离开 MainPage 类构造函数时,如下所示:

public MainPage()
{
    InitializeComponent();
}

我没有看到任何列表项。

那么,第一个问题:我想,基于绑定,应用会自动生成一个 User 实例并将其分配给列表?

正如我在调试器中看到的那样,实际上生成了一个 User 实例并将其分配给 BindingContext,但 ChangesList.ItemsSource 仍然为空。

因此,我更改了构造函数的代码:

public MainPage()
{
    InitializeComponent();
    var bc = BindingContext;
    var list = ChangesList.ItemsSource;
    ChangesList.ItemsSource = (bc as User).Changes;
}

这让我在编译和运行应用程序时可以看到一个包含项目的列表。此外,我可以通过“addItem”按钮后面的代码将新项目添加到列表中。但是:当我点击一个项目时,什么也没有发生。代码如下:

private void ListView_ItemTapped(object sender, ItemTappedEventArgs e)
{
    var change = e.Item as Change;
    change.IsVisible = !change.IsVisible;
}

Data 方法如下所示:

 public class Change : INotifyPropertyChanged
{
    public string Name { get; set; }
    bool isVisible = false;

    public event PropertyChangedEventHandler PropertyChanged;

    public bool IsVisible
    {
        get
        {
            return isVisible;
        }
        set
        {
            isVisible = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Change-IsVisible"));
        }
    }
}

因此第二个问题:为什么Button不改变其可见性状态而变得可见?

非常感谢您!

编辑:添加了完整的“更改”类代码。

编辑 2:用户代码。

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.ComponentModel;
using Xamarin.Forms;
using System.Diagnostics;

namespace App.ViewModels
{
    public class User : INotifyPropertyChanged
    {
        public string Username { get; set; }
        public ObservableCollection<Change> Changes = null;   
        public event PropertyChangedEventHandler PropertyChanged;

        public User()
        {
            Changes = new ObservableCollection<Change>();
            addChange("Test 1");
            addChange("Test 2");

        }

        public void addChange(string text)
        {
            Change c = new Change
            {
                Name = text,
                IsVisible = false
            };
            Changes.Add(c);
            refresh();
        }

        public void refresh()
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Changes"));
        }
    }
}

【问题讨论】:

  • 您的模型是否实现了 INotifyPropertyChanged?
  • 感谢您的提问。我想是这样。在第一篇文章中,我将“IsVisible”方法代码替换为完整的类代码。在那里你可以看到 Change ViewModel 实现了 INotifyPropertyChanged 方法。

标签: c# xamarin xamarin.forms


【解决方案1】:

对于第二个问题 - 尝试:

PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsVisible"));

对于第一个问题 - 能否请您分享您的用户源代码

【讨论】:

  • 非常感谢您回答了第二个问题!如此明显......对于第一个问题,我在我的初始帖子中添加了用户代码。
【解决方案2】:

尝试以下方法:

将 User 类中的 getter/setter 更改为:

public string Username
{
    get { return username;}
    set { username = value; OnPropertyChanged("Username");
}
private string username = string.Empty;

public ObservableCollection<Change> Changes
{
    get { return changes; }
    set { changes = value; OnPropertyChanged("Changes");
}
private ObservableCollection<Change> changes = null;

在类中添加一个新方法: 公共无效 OnPropertyChanged(字符串属性名称) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }

然后确保在 Changes 类中相应地实现上面修改过的代码。

最后在你的 MainPage 类构造函数中设置页面的绑定上下文:

public MainPage(User user)
{
    InitializeComponent();
    BindingContext = user;
}

一些解释: 绑定上下文必须包含您的数据模型类,在您的情况下是用户。

你在做什么

var bc = BindingContext;
ChangesList.ItemsSource = (bc as User).Changes;

正在尝试将您的 MainPage 的未设置 BindingContext 强制转换为用户,该用户将为空。

因此,为了在 Xaml 中使用 BindingContext,必须将其设置为用户类的实例,否则屏幕上不会显示任何数据。

【讨论】:

  • 嗨,Markus,非常感谢您的详细回答。一个问题:我必须以编程方式设置 BindingContext 吗?我想,如果我在 Mainpage.XAML 文件中定义它就足够了。
  • 我曾经从代码隐藏中执行此操作,但是鉴于您的用户类的构造函数可确保您拥有可用的数据,而不仅仅是一个用零值初始化的简单类对象,从主页 xaml 定义也应该这样做诡计。基本上,这在很大程度上取决于您的业务逻辑以及您如何处理数据。
  • 嗯好的,现在就可以了。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-12
  • 1970-01-01
  • 2014-08-05
  • 2020-12-17
  • 1970-01-01
  • 2023-03-09
相关资源
最近更新 更多