父列表属性更改后嵌套列表 UI 不更新 - Xamarin.Forms

问题描述

虽然这个问题似乎被问了很多次,但我似乎无法找到正确的解决方案,或者将各个部分放在一起来解决问题。

我有一个 CollectionView,在集合视图中有一个 Bindable.Stacklayout

嵌套的 Stacklayout 包含一个 CheckBox,并且该复选框的可见性由父列表(CollectionView)数据源的属性设置。

这最初在加载时工作正常,但是,一旦父属性发生变化(它还处理嵌套堆栈布局的可见性),则嵌套堆栈布局的 UI 不会更新。问题是,我怎样才能做到这一点?

XAML:

<CollectionView
    ItemsSource="{Binding RoomsData}"
    SelectionMode="None">

    <CollectionView.ItemTemplate>
        <DataTemplate>
            <xct:Expander
                x:Name="RoomExpander"
                IsExpanded="{Binding IsExpanded}">
                
                <xct:Expander.Header>
                    <! -- omitted code -->
                </xct:Expander.Header>
                
                <xct:Expander.Content>

                    <StackLayout                                
                        BindableLayout.ItemsSource="{Binding Elements}">
                        
                        <BindableLayout.ItemTemplate>
                            <DataTemplate>
                                <Grid>

                                    <!-- omitted / simplified code a bit for readability -->
                                    <CheckBox IsVisible="{Binding RoomsData.ElementsVisible}" />
                                    
                                </Grid>

                            </DataTemplate>
                        </BindableLayout.ItemTemplate>
                                                        
                    </StackLayout>
                                                
                </xct:Expander.Content>

            </xct:Expander>

        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

模型:

// Main datasource
public IList<RoomModel> RoomsData
{
    get { return _roomsData; }
    set { SetProperty(ref _roomsData,value); }
}

public class RoomModel : ObservableObject
{
    // Other properties omitted.. 

    private bool _elementsVisible;

    public bool ElementsVisible
    {
        get { return _elementsVisible; }
        set { SetProperty(ref _elementsVisible,value); }
    }

    public IList<ElementModel> Elements { get; set; }
}

public class ElementModel : ObservableObject
{
    // Other properties omitted.. 
}

*SetProperty 包含 NotifyPropertyChanged 逻辑

在某个时刻,ElementsVisible 属性从 false 变为 true,反之亦然,然后我希望嵌套 stacklayout 的复选框更改可见性,但没有任何反应。我应该通知 Elements 嵌套数据源来实现吗?

解决方法

根据 Jason 的意见,您对 Xamarin.Forms Relative Bindings 有一些问题,我做了一个示例,您可以看看。如果我更改 ElementsVisible,UI 将更新。

<StackLayout>
        <CollectionView
            x:Name="collectionview"
            ItemsSource="{Binding RoomsData}"
            SelectionMode="None">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <Expander x:Name="expander" IsExpanded="{Binding IsExpanded}">
                        <Expander.Header>
                            <Label
                                FontAttributes="Bold"
                                FontSize="Medium"
                                Text="test" />
                        </Expander.Header>
                        <StackLayout BindableLayout.ItemsSource="{Binding Elements}">
                            <BindableLayout.ItemTemplate>
                                <DataTemplate>
                                    <StackLayout>
                                        <!--  omitted / simplified code a bit for readability  -->
                                        <CheckBox IsVisible="{Binding Path=BindingContext.ElementsVisible,Source={x:Reference expander}}" />
                                        <Label Text="{Binding str}" />
                                    </StackLayout>
                                </DataTemplate>
                            </BindableLayout.ItemTemplate>
                        </StackLayout>
                    </Expander>

                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>

        <Button
            x:Name="btn1"
            Clicked="btn1_Clicked"
            Text="change data" />
    </StackLayout>
 public partial class Page11 : ContentPage
{
    public ObservableCollection<RoomModel> RoomsData { get; set; }
    public Page11()
    {
        InitializeComponent();
        RoomsData = new ObservableCollection<RoomModel>()
        {
            new RoomModel(){IsExpanded=true,ElementsVisible=true,Elements=new ObservableCollection<ElementModel>(){

                new ElementModel(){str="test 1"},new ElementModel(){str="test 12"},new ElementModel(){str="test 13"}}
            },new RoomModel(){IsExpanded=true,Elements=new ObservableCollection<ElementModel>(){

                new ElementModel(){str="test 2"},new ElementModel(){str="test 21"},new ElementModel(){str="test 23"}}
            },Elements=new ObservableCollection<ElementModel>(){

                new ElementModel(){str="test 3"},new ElementModel(){str="test 31"},new ElementModel(){str="test 32"}}
            },Elements=new ObservableCollection<ElementModel>(){

                new ElementModel(){str="test 4"},new ElementModel(){str="test 41"},new ElementModel(){str="test 43"}}
            }
        };

        this.BindingContext = this;
    }

    private void btn1_Clicked(object sender,EventArgs e)
    {
        RoomModel room = RoomsData.FirstOrDefault();
        room.ElementsVisible = false;
        collectionview.ItemsSource = RoomsData;
    }
}

public class RoomModel:ViewModelBase
{
    // Other properties omitted.. 
    private bool _IsExpanded;
    public bool IsExpanded
    {
        get { return _IsExpanded; }
        set
        {
            _IsExpanded = value;
            RaisePropertyChanged("IsExpanded");
        }
    }
    private bool _elementsVisible;
    public bool ElementsVisible
    {
        get { return _elementsVisible; }
        set
        {
            _elementsVisible = value;
            RaisePropertyChanged("ElementsVisible");
        }
    }
    public ObservableCollection<ElementModel> Elements { get; set; }
}
public class ElementModel 
{
    public string str { get; set; }
}

ViewModelBase 是实现 INotifyPropertyChanged 的​​类。

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