【问题标题】:Listview not updated when isVisible is set to true当 isVisible 设置为 true 时,Listview 未更新
【发布时间】:2016-06-13 14:25:47
【问题描述】:

我正在尝试制作带有可点击行的ListView。当您单击一行时,它会将子堆栈布局设置为可见性。这在android中可以正常工作,但在ios中不行。也许我做错了。我仍然是初学者,知道如何解决这个问题或任何其他更好的方法吗? 问题是它在 ios 上打开,因此可见性发生了变化,但它不会更新单元格的高度。例如,如果您向上滚动直到看不到打开的单元格,然后再向下滚动,单元格就会在屏幕外更新。你会看到它已经更新了高度。

我尝试使用自定义渲染器,但我不知道从哪里开始。

这是我的 xaml:

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Lisa.Excelsis.Mobile.AssessmentPage" xmlns:local="clr-namespace:Lisa.Excelsis.Mobile;assembly=Lisa.Excelsis.Mobile">
<StackLayout>
    <local:SpecialListView x:Name="CategoryList" 
                ItemsSource = "{Binding Categories}" 
                HasUnevenRows="true" 
                RowHeight="-1" 
                GroupDisplayBinding="{Binding Name}"
                IsGroupingEnabled="true">
        <local:SpecialListView.ItemTemplate>
            <DataTemplate> 
                <ViewCell x:Name="ObservationCell">
                    <ViewCell.View>
                        <StackLayout x:Name="ObservationContainer"
                                     HorizontalOptions="FillAndExpand"
                                     Orientation="Vertical"
                                     VerticalOptions="StartAndExpand"
                                     BackgroundColor="White">   
                            <StackLayout x:Name="Observation"   
                                         HorizontalOptions="FillAndExpand"
                                         VerticalOptions="StartAndExpand"                                        
                                         Padding="15, 10, 10, 10"
                                         BackgroundColor="White">   
                                <StackLayout.GestureRecognizers>
                                    <TapGestureRecognizer Tapped="OpenItem"/>
                                </StackLayout.GestureRecognizers>

                                <Grid HorizontalOptions="FillAndExpand" >
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto" />     
                                        <RowDefinition Height="Auto" />                 
                                    </Grid.RowDefinitions>
                                   
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="35" />
                                        <ColumnDefinition Width="*" />
                                    </Grid.ColumnDefinitions>

                                    <Label  x:Name="ObservationOrder" 
                                            Text="{Binding Criterion.Order, StringFormat='{0}.'}" 
                                            FontSize="18" 
                                            VerticalOptions="StartAndExpand" 
                                            Grid.Column="0" Grid.Row="0"/>   

                                    <Label  x:Name="ObservationTitle" 
                                            Text="{Binding Criterion.Title}" 
                                            FontSize="18" 
                                            VerticalOptions="StartAndExpand" 
                                            Grid.Column="1" Grid.Row="0"/>
                                    
                                </Grid>
                            </StackLayout>
                            <StackLayout x:Name="ObservationButtons"
                                         HorizontalOptions="FillAndExpand"
                                         VerticalOptions="StartAndExpand"
                                         BackgroundColor="White"
                                         IsVisible="false"
                                         Padding="0, 0, 0, 20"
                                         ClassId = "{Binding Id, StringFormat='ObservationButtons_{0}'}">

                                <Grid HorizontalOptions="Center"                                         
                                      Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto" />                 
                                    </Grid.RowDefinitions>

                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="80" />
                                        <ColumnDefinition Width="80" />
                                        <ColumnDefinition Width="10" />
                                        <ColumnDefinition Width="80" />
                                        <ColumnDefinition Width="80" />
                                        <ColumnDefinition Width="80" />
                                        <ColumnDefinition Width="80" />
                                    </Grid.ColumnDefinitions>

                                    <StackLayout Grid.Column="0" Grid.Row="0" >
                                        <Image  Source="yesnobutton0.png" 
                                                HeightRequest="60" WidthRequest="60"
                                                HorizontalOptions="Center"
                                                VerticalOptions="Start"
                                                x:Name="yesImage">   
                                            <Image.GestureRecognizers>
                                                <TapGestureRecognizer Tapped="SetYesImage"/>
                                            </Image.GestureRecognizers>
                                        </Image>

                                        <Label Text="Ja" VerticalOptions="End" HorizontalOptions="Center"/>
                                    </StackLayout>

                                    <StackLayout Grid.Column="1" Grid.Row="0">
                                        <Image  Source="yesnobutton0.png"
                                                HeightRequest="60" WidthRequest="60"
                                                HorizontalOptions="Center"
                                                VerticalOptions="Start"
                                                x:Name="noImage">
                                            <Image.GestureRecognizers>
                                                <TapGestureRecognizer Tapped="SetNoImage"/>
                                            </Image.GestureRecognizers>
                                        </Image>
                                            
                                        <Label Text="Nee" VerticalOptions="End" HorizontalOptions="Center"/>
                                    </StackLayout>

                                    <Image  Source="maybenot.png"
                                            HeightRequest="60" WidthRequest="60"
                                            HorizontalOptions="Center"
                                            VerticalOptions="Start"
                                            Grid.Column="3" Grid.Row="0">
                                        <Image.GestureRecognizers>
                                            <TapGestureRecognizer Tapped="SetMark"/>
                                        </Image.GestureRecognizers>
                                    </Image>

                                    <Image  Source="skip.png"
                                            HeightRequest="60" WidthRequest="60"
                                            HorizontalOptions="Center"
                                            VerticalOptions="Start"
                                            Grid.Column="4" Grid.Row="0">
                                        <Image.GestureRecognizers>
                                            <TapGestureRecognizer Tapped="SetMark"/>
                                        </Image.GestureRecognizers>
                                    </Image>

                                    <Image  Source="unclear.png"
                                            HeightRequest="60" WidthRequest="60"
                                            HorizontalOptions="Center"
                                            VerticalOptions="Start"
                                            Grid.Column="5" Grid.Row="0">
                                        <Image.GestureRecognizers>
                                            <TapGestureRecognizer Tapped="SetMark"/>
                                        </Image.GestureRecognizers>
                                    </Image>

                                    <Image  Source="change.png"
                                            HeightRequest="60" WidthRequest="60"
                                            HorizontalOptions="Center"
                                            VerticalOptions="Start"
                                            Grid.Column="6" Grid.Row="0">
                                        <Image.GestureRecognizers>
                                            <TapGestureRecognizer Tapped="SetMark"/>
                                        </Image.GestureRecognizers>
                                    </Image>
                                </Grid>
                            </StackLayout>
                        </StackLayout>
                    </ViewCell.View>
                </ViewCell>
            </DataTemplate>
        </local:SpecialListView.ItemTemplate>
    </local:SpecialListView>
</StackLayout>

这是它如何在 android 上运行以及我希望它如何在 ios 上运行的示例。

【问题讨论】:

  • 你试过在你的布局上调用 ForceLayout()

标签: ios listview xamarin expandablelistview xamarin.forms


【解决方案1】:

我在一个小型测试项目中重现了您的问题。我更喜欢通过数据绑定进行布局更改,而不是代码后面。

让我们从模板开始:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
              x:Class="App6.Page1">
  <ListView x:Name="CategoryList"
            BackgroundColor="Gray"
            ItemsSource="{Binding Categories}"
                SelectedItem="{Binding SelectedItem}"
                HasUnevenRows="true"
                RowHeight="-1">
    <ListView.ItemTemplate>
      <DataTemplate>
        <ViewCell x:Name="ObservationCell">
          <ViewCell.View>
            <StackLayout x:Name="Observation"
                        HorizontalOptions="FillAndExpand"
                        VerticalOptions="StartAndExpand"
                        Padding="15, 10, 10, 10"
                        BackgroundColor="White">

              <Label  x:Name="ObservationTitle"
                      Text="{Binding Title}"
                      FontSize="18"
                      TextColor="Black"
                      VerticalOptions="StartAndExpand"/>

              <StackLayout Orientation="Horizontal" IsVisible="{Binding IsSelected}">
                <Image BackgroundColor="Fuchsia" WidthRequest="40" HeightRequest="40"></Image>
                <Image BackgroundColor="Green" WidthRequest="40" HeightRequest="40"></Image>
                <Image BackgroundColor="Yellow" WidthRequest="40" HeightRequest="40"></Image>
                <Image BackgroundColor="Blue" WidthRequest="40" HeightRequest="40"></Image>
                <Image BackgroundColor="Black" WidthRequest="40" HeightRequest="40"></Image>
              </StackLayout>
            </StackLayout>
          </ViewCell.View>
        </ViewCell>
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>
</ContentPage>

Datatemplate基本相同,但是:

  • StackLayout 没有 Click-Listener
  • StackLayout 的可见性绑定到IsSelected (IsVisible="{Binding IsSelected}")
  • ListViewSelectedItem 绑定到我们 ViewModel 的 SelectedItem

我们的页面只是将ViewModel设置为DataContext

public partial class Page1 : ContentPage
{
    public Page1()
    {
        InitializeComponent();
        BindingContext = new Page1ViewModel();
    }
}

ViewModel

  • 实现INotifyPropertyChanged 以通知视图有关数据更改
  • 在我们的Categories 收藏中添加了一些虚拟物品
  • 具有更新类别的IsSelected 属性的SelectedItem 属性
class Page1ViewModel : INotifyPropertyChanged
{
    private Category _selectedItem;
    private ObservableCollection<Category> _categories = new ObservableCollection<Category>();
    public event PropertyChangedEventHandler PropertyChanged;

    public ObservableCollection<Category> Categories
    {
        get { return _categories; }
        set
        {
            _categories = value;
            OnPropertyChanged();
        }
    }

    public Category SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            if (_selectedItem == value)
                return;

            if (_selectedItem != null)
            {
                _selectedItem.IsSelected = false;
            }

            _selectedItem = value;
            if (_selectedItem != null)
            {
                _selectedItem.IsSelected = true;
            }
        }
    }

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public Page1ViewModel()
    {
        Categories.Add(new Category());
        Categories.Add(new Category());
        Categories.Add(new Category());
        Categories.Add(new Category());
        Categories.Add(new Category());
    }
}

最后但并非最不重要但最重要的是,您需要一个覆盖默认渲染器的小型自定义渲染器。如果SelectedItem 已更改,我们将调用ReloadData()

[assembly: ExportRenderer(typeof(ListView), typeof(MyListViewRenderer))]
namespace App6.iOS.CustomRenderer
{
    public class MyListViewRenderer : ListViewRenderer
    {
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
            if (e.PropertyName == ListView.SelectedItemProperty.PropertyName)
            {
                Device.BeginInvokeOnMainThread(() => Control.ReloadData());
            }
        }
    }
}

结果

【讨论】:

  • 可以通过重新加载您单击的行来完成吗?
  • 也许吧。但是ReloadData 是 iOS 中向UITableView 发送数据更改信号的常用方法。这就是我选择这种方法的原因。因此,如果您关心性能,我假设它以某种方式进行了优化。
  • 您好,我遇到了同样的问题。我有一些额外的行为:如果我再次单击一行,我想停用它(在 viewModel 中 if (SelectedItem == value) { SelectedItem.IsSelected = false; // 将折叠子菜单 SelectedItem = null; // 不' t 触发 SelectedItem 属性,因此,自定义渲染器不会调用 ReloadData }
猜你喜欢
  • 1970-01-01
  • 2017-06-28
  • 1970-01-01
  • 1970-01-01
  • 2015-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-25
相关资源
最近更新 更多