Xamarin.Forms, XAML, Bindings and isVisible

喜欢而已 提交于 2021-01-29 12:30:33

问题


I am (obviously, regarding the question) new to this, so thanks in advance for any help! As I am trying my current best on this for hours now, I hope, someone can accelerate my learning curve :)

Addendum: I also posted on the Xamarin Forum, however this seems to be rather dead regarding the amount of answers to questions. Therefore I hope no one takes offense.

So, I have my XAML MainPage:

<?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>

I have a datamodel with the correponding attributes behind. When I leave the MainPage class constructor like the following:

public MainPage()
{
    InitializeComponent();
}

I see no list items.

So, first Question: I thought, based on the bindings, the app would automatically generate a User instance and assign it to the list?

As I can see with the debugger, a User instance actually is generated and also assigned to the BindingContext, but the ChangesList.ItemsSource remains null.

Therefore, I changed the code of the constructor:

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

This lets me see a list with items when I compile and run the app. Also, I can add new items to the list via the code behind the 'addItem' Button. However: Nothing happens, when I tap an item. The code looks like follows:

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

and the Data methods look as follows:

 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"));
        }
    }
}

Therefore the second question: Why does the Button not change its visibility status and become visible?

Thank you very much in advance!

Wolf

Edit: Added the complete "Change" Class Code.

Edit 2: The User Code.

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"));
        }
    }
}

回答1:


For the 2nd question - try:

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

For the first question - can you please share your User source code




回答2:


Try the following:

Change the getters/setters in your User class to:

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;

Add a new method to the class: public void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }

Then make sure that you implement the modified code above accordingly in your Changes class.

Finally in your MainPage class constructor set the binding context of the page:

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

Some explanation: The binding context has to contain your datamodel classes, in your case User.

What you are doing with

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

is trying to cast the unset BindingContext of your MainPage to User, which will be empty.

So in order to use the BindingContext in your Xaml, it MUST be set to an instance of your user class or else there is no data to be shown on the screen.



来源:https://stackoverflow.com/questions/52122765/xamarin-forms-xaml-bindings-and-isvisible

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!