在展开时更新列表视图

时间:2018-03-07 05:14:07

标签: xamarin xamarin.forms xamarin.ios

我正在编写一个Xamarin.Forms项目并且我有一个列表视图但是每当我显示隐藏的内容时,例如,使一个条目可见,ViewCell会重叠它下面的那个。

我有没有办法.Update()列表视图或其他东西来刷新它并让它们全部适合。

我不希望刷新让它回到顶端。

当我展示某些东西时,Android似乎能够自动更新高度。

我尝试使用HasUnevenRows="True",但仍然没有修复它。

代码:

Message.xaml

<StackLayout>
        <local:PostListView x:Name="MessageView" HasUnevenRows="True" IsPullToRefreshEnabled="True" Refreshing="MessageView_Refreshing" SeparatorVisibility="None" BackgroundColor="#54a0ff">
            <local:PostListView.ItemTemplate>
                <DataTemplate>
                    <local:PostViewCell>
                        <StackLayout>
                            <Frame CornerRadius="10" Padding="0" Margin="10, 10, 10, 5" BackgroundColor="White">
                                <StackLayout>
                                    <StackLayout x:Name="MessageLayout" BackgroundColor="Transparent" Padding="10, 10, 15, 10">
                                        ...
                                        <Label Text="{Binding PostReply}" FontSize="15" TextColor="Black" Margin="10, 0, 0, 10" IsVisible="{Binding ShowReply}"/>
                                        <StackLayout Orientation="Vertical" IsVisible="{Binding ShowReplyField}" Spacing="0">
                                            <Entry Text="{Binding ReplyText}" Placeholder="Reply..." HorizontalOptions="FillAndExpand" Margin="0, 0, 0, 5"/>
                                            ...
                                        </StackLayout>
                                        <StackLayout x:Name="MessageFooter" Orientation="Horizontal" IsVisible="{Binding ShowBanners}">
                                            <StackLayout Orientation="Horizontal">
                                                ...
                                                <Image x:Name="ReplyIcon" Source="reply_icon.png" HeightRequest="20" HorizontalOptions="StartAndExpand" IsVisible="{Binding ShowReplyButton}">
                                                    <Image.GestureRecognizers>
                                                        <TapGestureRecognizer Command="{Binding ReplyClick}" CommandParameter="{Binding .}"/>
                                                    </Image.GestureRecognizers>
                                                </Image>
                                                ... 
                                            </StackLayout>
                                            ...
                                        </StackLayout>
                                    </StackLayout>
                                </StackLayout>
                            </Frame>
                        </StackLayout>
                    </local:PostViewCell>
                </DataTemplate>
            </local:PostListView.ItemTemplate>
        </local:PostListView>
    </StackLayout>

Message.cs

    using Newtonsoft.Json;
 using SocialNetwork.Classes;
 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace SocialNetwork
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MessagePage : ContentPage
{
    public MessagePage()
    {
        InitializeComponent();
        LoadPage();
    }

    private async void LoadPage()
    {
        await LoadMessages();
    }

    private async void RefreshPage()
    {
        await LoadMessages();
        MessageView.EndRefresh();
    }

    private async Task LoadMessages()
    {
        //*Web Request*
        MessageView.ItemsSource = FormatPosts(this, Navigation, page_result);
        ...
    }

    public IList<MessageObject> FormatPosts(Page page, INavigation navigation, string json)
    {
        IList<MessageObject> Posts = new List<MessageObject>() { };
        var messages = JsonConvert.DeserializeObject<List<Message>>(json);

        foreach (var message in messages)
        {
            MessageObject mo = MessageObject.CreateMessage(...);
            Posts.Add(mo);
        }

        return Posts;
    }
    public async void ShowOptionActions(string id, string poster_id, object message)
    {
        ...
    }

    public async void ShowReportOptions(string id, string poster_id)
    {
        ...
    }

    public void SubmitReplyClick(string id, object msg)
    {
        ...
    }

    public async void SendReplyAsync(string id, object msg, string reply)
    {
        await SendReply(id, msg, reply);
    }

    public void ReplyCommandClick(string id, object msg)
    {
        MessageObject message = (MessageObject) msg;
        message.ShowReplyField = message.ShowReplyField ? false : true;
        //Update Cell Bounds
    }

    private async Task SendReply(string id, object msg, string reply)
    {
        MessageObject message = (MessageObject)msg;
        ...
        message.PostReply = reply;

        //Update Cell Bounds
    }

    public async void LikeMessageClick(string id, object message)
    {
        await LikeMessage(id, message);
    }

    private async Task LikeMessage(string id, object msg)
    {
       ...
    }

    public async void DeleteMessage(string id, object msg)
    {
        MessageObject message = (MessageObject)msg;

        message.ShowBanners = false;
        message.ShowReply = false;

        ...

        //Update Cell Bounds
    }

    public async Task ReportMessage(...)
    {
        ...
    }

    private void MessageView_Refreshing(object sender, EventArgs e)
    {
        RefreshPage();
    }
}

public class MessageObject : INotifyPropertyChanged
{
    private Boolean showBannersValue = true;
    private string replyValue = String.Empty;
    private bool showReplyValue;
    private bool showReplyButtonValue;
    private bool showReplyFieldValue;
    private Command replyCommandValue;
    private Command replySubmitValue;
    private string replyTextValue;
     ...

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private MessageObject(...)
    {
        ...
    }

    public static MessageObject CreateMessage(...)
    {
        return new MessageObject(...);
    }

    public Boolean ShowBanners
    {
        get
        {
            return this.showBannersValue;
        }

        set
        {
            if (value != this.showBannersValue)
            {
                this.showBannersValue = value;
                NotifyPropertyChanged();
            }
        }
    }

    public Boolean ShowReplyField
    {
        get
        {
            return this.showReplyFieldValue;
        }

        set
        {
            if(value != this.showReplyFieldValue)
            {
                this.showReplyFieldValue = value;
                NotifyPropertyChanged();
            }
        }
    }

    public string PostReply
    {
        get
        {
            return this.replyValue;
        }

        set
        {
            if (value != this.replyValue)
            {
                this.replyValue = value;
                NotifyPropertyChanged();
            }
        }
    }

    public Boolean ShowReply
    {
        get
        {
            return this.showReplyValue;
        }

        set
        {
            if(value != this.showReplyValue)
            {
                this.showReplyValue = value;
                NotifyPropertyChanged();
            }
        }
    }

    public Boolean ShowReplyButton
    {
        get
        {
            return this.showReplyButtonValue;
        }

        set
        {
            if (value != this.showReplyButtonValue)
            {
                this.showReplyButtonValue = value;
                NotifyPropertyChanged();
            }
        }
    }

      public string ReplyText
    {
        get
        {
            return this.replyTextValue;
        }

        set
        {
            if(value != this.replyTextValue)
            {
                this.replyTextValue = value;
                NotifyPropertyChanged();
            }
        }
    }

    public Command ReplyClick
    {
        get
        {
            return this.replyCommandValue;
        }

        set
        {
            if (value != this.replyCommandValue)
            {
                this.replyCommandValue = value;
                NotifyPropertyChanged();
            }
        }
    }

    ...

}
}

3 个答案:

答案 0 :(得分:1)

特别是对于iOS,根据单元格的变化,在ListView中调整行的大小会有问题(请参阅here)。 Cell上有一个方法ForceUpdateSize,它应该通知ListView单元格的大小已经更改,这会导致ListView调整其行的大小。

答案 1 :(得分:1)

IList<MessageObject>方法返回的FormatPosts保存在字段IList<MessageObject> _messages = new List<MessageObject>()

使用以下代码段随时更新ListView,包括检查设备是否在iOS上运行:

if(Device.RuntimePlatform == Device.iOS) 
{ 
    MessageView.ItemsSource = null; 
    MessageView.ItemsSource = _messages; 
}

答案 2 :(得分:0)

哦,我面对同样的事情。 我想你只需要在listview中的某处添加:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Grid Grid.row='0'>
    ...
    </Grid>

 // This, in my case, makes my cell expand when it's true. Normal behavior
    <Grid Grid.row='1' isVisible="{Binding Expand}">
    ...
    </Grid>
</Grid>

另外,如果您想单独更新单元格,我使用CustomObservableCollection:

public class CustomObservableCollection<T> : ObservableCollection<T>
    {
        public CustomObservableCollection() { }
        public CustomObservableCollection(IEnumerable<T> items) : this()
        {
            foreach(var item in items)
                this.Add(item);
        }
        public void ReportItemChange(T item)
        {
            NotifyCollectionChangedEventArgs args =
                new NotifyCollectionChangedEventArgs(
                    NotifyCollectionChangedAction.Replace,
                    item,
                    item,
                    IndexOf(item));
            OnCollectionChanged(args);
        }
    }

使用Custom ListView执行ItemClickCommand:

public class CustomListView : ListView
    {
#pragma warning disable 618
        public static BindableProperty ItemClickCommandProperty = BindableProperty.Create<CustomListView, ICommand>(x => x.ItemClickCommand, null);
#pragma warning restore 618

        public CustomListView(ListViewCachingStrategy cachingStrategy = ListViewCachingStrategy.RetainElement) :
                base(cachingStrategy)
        {
            this.ItemTapped += this.OnItemTapped;
        }

        public ICommand ItemClickCommand
        {
            get { return (ICommand)this.GetValue(ItemClickCommandProperty); }
            set { this.SetValue(ItemClickCommandProperty, value); }
        }

        private void OnItemTapped(object sender, ItemTappedEventArgs e)
        {
            if(e.Item != null && this.ItemClickCommand != null && this.ItemClickCommand.CanExecute(e.Item))
            {
                this.ItemClickCommand.Execute(e.Item);
                this.SelectedItem = null;
            }
        }
    }

然后在xaml:

...
...
<Customs:CustomListView
      HasUnevenRows="true"
      ItemsSource="{Binding PersonList}"
      IsPullToRefreshEnabled="True"
      RefreshCommand="{Binding DoRefreshCommand}"
      ItemClickCommand="{Binding ItemClickCommand}">
...
...
</Customs:CustomListView>

最后:

public Command<Person> ItemClickCommand { get; set; }
...
ItemClickCommand = new Command<Person>(SelectionExecute);
...
private void SelectionExecute(Person arg)
        {
            arg.Expand = !arg.Expand;

            foreach(var item in PersonList)
            {
                if(item.Key == arg.Id)// you will change this probably 
                    item.ReportItemChange(arg);
            }
        }

希望它有所帮助:)