嵌套列表 UI 在父列表 属性 更改后未更新 - Xamarin.Forms
Nested list UI not updating after parent list property changes - 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,反之亦然,然后我希望嵌套堆栈布局的复选框改变可见性,但没有任何反应。我是否应该通知 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,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 class 实现了 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));
}
}
}
虽然这个问题好像被问了很多次,但我似乎找不到正确的解决方案,或者把各个部分放在一起来解决这个问题。
我有一个 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
嵌套数据源来实现这一点?
按照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 class 实现了 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));
}
}
}