【问题标题】:Nested list UI not updating after parent list property changes - Xamarin.Forms父列表属性更改后嵌套列表 UI 未更新 - Xamarin.Forms
【发布时间】:2021-04-26 13:11:51
【问题描述】:

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

我有一个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,反之亦然,然后我预计嵌套堆栈布局的复选框会改变可见性,但没有任何反应。我应该通知Elements 嵌套数据源来实现这一点吗?

【问题讨论】:

  • 您的绑定表达式为{Binding RoomsData.ElementsCheckboxVisible},但您的属性名为ElementsVisible
  • 我的错,这是一个错字:) 将其复制到此处时更改了属性名称以提高可读性。现在改了。
  • 即使RoomsData 没有任何属性,它只是一个集合。如果要绑定到父级上的属性,您可能需要查看相对绑定
  • 您需要使用我之前建议的相对绑定。 docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/…
  • 只是我发布的参考。我希望您想使用父级,因为您正在尝试访问父级绑定到元素的属性

标签: xamarin.forms xamarin-binding


【解决方案1】:

在 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,ElementsVisible=true,Elements=new ObservableCollection<ElementModel>(){

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

                new ElementModel(){str="test 3"},new ElementModel(){str="test 31"},new ElementModel(){str="test 32"}}
            },
               new RoomModel(){IsExpanded=true,ElementsVisible=true,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));
        }
    }
}

【讨论】:

  • 非常感谢您提供的示例!这确实成功了。最后我是相对绑定错误的东西。
猜你喜欢
  • 2013-03-02
  • 2011-05-22
  • 1970-01-01
  • 2010-11-10
  • 1970-01-01
  • 1970-01-01
  • 2013-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多