如何在c#和XAML中刷新ListBox以显示最新数据?



我在页面中填充了一个ListBox,其中包含来自webservice的一些数据,一个评论回复列表。在同一页面上有一个文本框和一个帖子按钮,允许用户在RepliesPage上对评论发表回复。当我运行应用程序并发布回复时,列表不会立即更新,直到我离开页面并导航回页面时,我才会看到新回复添加到列表中。我怎么才能避开这个问题?页面的XAML

<phone:PhoneApplicationPage
x:Class="CeFlix.Views.RepliesPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d"
xmlns:cimbalinoBehaviors="clr-namespace:Cimbalino.Phone.Toolkit.Behaviors;assembly=Cimbalino.Phone.Toolkit"
xmlns:cimbalinoHelpers="clr-namespace:Cimbalino.Phone.Toolkit.Helpers;assembly=Cimbalino.Phone.Toolkit.Background"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
shell:SystemTray.IsVisible="True"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
xmlns:UserControl="clr-namespace:CeFlix.UserControls">
<i:Interaction.Behaviors>
    <cimbalinoBehaviors:ApplicationBarBehavior>
        <cimbalinoBehaviors:ApplicationBarIconButton x:Name="postReply"
                                                         Text="post"
                                                         IconUri="/Assets1/AppBar/send.text.png"
                                                         IsEnabled="True"
                                                         Command="{Binding UserSubmitReplyCommand,Mode=TwoWay}"/>
        <!--<cimbalinoBehaviors:ApplicationBarIconButton x:Name="home"
                                                         Text="home"
                                                         IconUri="/Assets1/AppBar/basecircle.png"
                                                         IsEnabled="True"
                                                         Click="home_Click"/>-->
    </cimbalinoBehaviors:ApplicationBarBehavior>
</i:Interaction.Behaviors>
<!--<phone:PhoneApplicationPage.ApplicationBar>
    <shell:ApplicationBar>
        <shell:ApplicationBarIconButton x:Name="postReply" 
                                        IconUri="/Assets1/AppBar/send.text.png" 
                                        IsEnabled="True" Text="Post"
                                        Click="UserSubmitReplyCommand"/>
    </shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>-->
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="#0C426B">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    <!--TitlePanel contains the name of the application and page title-->
    <StackPanel  x:Name="TitlePanel" Orientation="Horizontal" Grid.Row="0" Style="{StaticResource ContentHeaderStyle}" Height="72">
        <Button  Command="{Binding Path=ClickShowPopUpCommand,Mode=TwoWay}" Style="{StaticResource ButtonStyle}" Height="65">
            <StackPanel Orientation="Horizontal">
                <Image Source="/Images/logo.png" Height="45" Margin="20,0,0,0"/>
                <TextBlock Text="REPLIES" Margin="20,0,0,0" Style="{StaticResource PhoneTextTitle2Style}" Foreground="#0C426B" FontWeight="Bold" FontFamily="Segoe WP Black"/>
            </StackPanel>
        </Button>
    </StackPanel>
    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" >
        <ListBox x:Name="lbxReplies"
                 ItemsSource="{Binding ReplyList,Mode=TwoWay}"
             Margin="0,0,-12,0" 
             >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="auto"/>
                            <ColumnDefinition Width="400"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="auto"/>
                        </Grid.RowDefinitions>
                        <Ellipse Width="50" Height="50" Margin="8" VerticalAlignment="Top">
                            <Ellipse.Fill>
                                <ImageBrush ImageSource="{Binding profile_pic}"/>
                            </Ellipse.Fill>
                        </Ellipse>
                        <Border Grid.ColumnSpan="2" Grid.Row="0" HorizontalAlignment="Stretch" BorderBrush="Black" BorderThickness="0,0,0,0.5"/>
                        <StackPanel   Grid.Column="1">
                            <TextBlock  VerticalAlignment="Center" HorizontalAlignment="Left"  FontSize="16" Text="{Binding username}" Foreground="#FFF8DE7E" FontFamily="Consolas" />
                            <TextBlock  VerticalAlignment="Center" 
                                        HorizontalAlignment="Left"  
                                        FontSize="16" Text="{Binding comment}" 
                                        TextWrapping="Wrap"
                                        TextOptions.DisplayColorEmoji="True"
                                        TextOptions.TextHintingMode="Animated"
                                        TextTrimming="WordEllipsis" Foreground="White" FontFamily="Consolas" />
                        </StackPanel>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
    <StackPanel Orientation="Horizontal" Grid.Row="2">
        <TextBox x:Name="replyTextBox" 
                 Width="475" 
                 Text="{Binding Message,Mode=TwoWay}"
                 TextChanged="replyTextBox_TextChanged"
                 BorderThickness="0"
                 GotFocus="replyTextBox_GotFocus">
            <TextBox.Background>
                <ImageBrush ImageSource="/Assets/watermark2.png"/>
            </TextBox.Background>
            <TextBox.InputScope>
                <InputScope>
                    <InputScopeName NameValue="Text" />
                </InputScope>
            </TextBox.InputScope>
        </TextBox>
        <
    </StackPanel>
    <UserControl:DataLoading x:Name="loaderForReplies" Grid.RowSpan="2"  Visibility="{Binding LoaderForReplyVisibility}" />
</Grid>

背后的代码
 protected async override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
       string parameter = this.NavigationContext.QueryString["parameter"];
        BaseViewModel.SelectedCommentID = parameter;

    }
    private async void ContentPanel_Loaded(object sender, RoutedEventArgs e)
    {

        await repliesViewModel.GetReplyList();
        this.DataContext = this.repliesViewModel;
        lbxReplies.ItemsSource = null;
        lbxReplies.ItemsSource = repliesViewModel.ReplyList;
    }

这是ViewModel代码

using CeFlix.Common;
using CeFlix.Entities;
using CeFlix.OtherEntities;
using Microsoft.Phone.Tasks;
using Microsoft.Xna.Framework.Media;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Xml.Linq;
using Windows.Storage;
namespace CeFlix.ViewModels
{
    public class RepliesViewModel : BaseViewModel
    {
        #region Properties
    private UserStatusData userStatusData;
    public UserStatusData UserStatusData
    {
        get
        {
            return this.userStatusData;
        }
        set
        {
            SetProperty(ref userStatusData, value);
        }
    }
    private string message;
    public string Message
    {
        get
        {
            return message;
        }
        set
        {
            SetProperty(ref message, value);
        }
    }
    private Visibility replyListControlVisibility = Visibility.Visible;
    public Visibility ReplyListControlVisibility 
    {
        get 
        { 
            return this.replyListControlVisibility;
        }
        set 
        { 
            SetProperty(ref replyListControlVisibility, value);
        } 
    }
    private Visibility userReplyPopUpOpen;
    public Visibility UserReplyPopupOpen 
    {
        get 
        { 
            return this.userReplyPopUpOpen;
        }
        set 
        { 
            SetProperty(ref this.userReplyPopUpOpen, value);
        } 
    }
    private Visibility loaderForReplyVisibility = Visibility.Collapsed;
    public Visibility LoaderForReplyVisibility
    {
        get
        {
            return this.loaderForReplyVisibility;
        }
        set
        {
            SetProperty(ref this.loaderForReplyVisibility, value);
        }
    }
    private Visibility signInPopUpVisibility = Visibility.Collapsed;
    public Visibility SignInPopUpVisibility
    {
        get
        {
            return this.signInPopUpVisibility;
        }
        set
        {
            SetProperty(ref this.signInPopUpVisibility, value);
        }
    }
    private ObservableCollection<Reply> replyList;
    public ObservableCollection<Reply> ReplyList
    {
        get
        {
            return replyList;
        }
        set
        {
            SetProperty(ref this.replyList, value);
        }
    }
    private ReplyDetails replyDetailsData;
    public ReplyDetails ReplyDetailsData 
    {
        get 
        { 
            return this.replyDetailsData;
        }
        set 
        { 
            SetProperty(ref this.replyDetailsData, value);
        } 
    }
    // Comment
    private CommentDetails comment;
    public CommentDetails Comment
    {
        get
        {
            return this.comment;
        }
        set
        {
            SetProperty(ref this.comment, value);
        }
    }
    private Comment selectedComment;
    public Comment SelectedComment 
    {
        get 
        { 
            return this.selectedComment;
        }
        set 
        {
            SetProperty(ref this.selectedComment, value);
            if (value != null)
            {
                BaseViewModel.SelectedCommentID = this.selectedComment.id;
                this.GetCommentDetail();
                this.GetReplyList();
            }
        } 
    }
    private CommentDetails commentsDetailsData;
    public CommentDetails CommentsDetailsData
    {
        get
        {
            return this.commentsDetailsData;
        }
        set
        {
            SetProperty(ref this.commentsDetailsData, value);
        }
    }
    private CeFlix.Entities.Detail videoDetail;
    public CeFlix.Entities.Detail VideoDetail
    {
        get
        {
            return this.videoDetail;
        }
        set
        {
            SetProperty(ref this.videoDetail, value);
        }
    }
    private CeFlix.Entities.VideoDetails videoDetailData;
    public CeFlix.Entities.VideoDetails VideoDetailData
    {
        get
        {
            return this.videoDetailData;
        }
        set
        {
            SetProperty(ref this.videoDetailData, value);
        }
    }
    #endregion
    #region Constructor
    public RepliesViewModel()
    {
        this.ReplyList = new ObservableCollection<Reply>();
    }
    #endregion
    #region Single Instance could be replacement for Singleton that I know of
    private static RepliesViewModel currentInstance = null;
    public static RepliesViewModel GetSingleInstance()
    {
        if (currentInstance == null)
        {
            currentInstance = new RepliesViewModel();
        }
        return currentInstance;
    }
    #endregion
    #region Delegate Commands
    private DelegateCommand goHome;
    public DelegateCommand GoHome
    {
        get
        {
            if (goHome == null)
                goHome = new DelegateCommand(GoHomeCommandClick);
            return goHome;
        }
    }
    private DelegateCommand userSubmitReplyCommand;
    public DelegateCommand UserSubmitReplyCommand
    {
        get
        {
            if (userSubmitReplyCommand == null)
                userSubmitReplyCommand = new DelegateCommand(UserSubmitReplyCommandClick);
            return userSubmitReplyCommand;
        }
    }
    #endregion
    #region Methods
    private void GoHomeCommandClick()
    {
        BaseViewModel.NavigationService.NavigateToPage(Entities.Enums.Views.DashboardPage);
    }
    public async Task GetCommentDetail()
    {
        try
        {
            string Api_Url = string.Format(Constants.LoadComment_API, BaseViewModel.SelectedCommentID) + "?timestamp" + DateTime.Now.ToString();
            if (BaseViewModel.HelperClass.IsInternet())
            {
                var response = await BaseViewModel.HelperClass.Get(Api_Url);
                var selectedCommentDetails = JSONHelper.DeserializeFromJson<CeFlix.Entities.CommentDetails>(response);
                // this.SelectedComment = selectedCommentDetails.Comments;
                foreach (Comment item in selectedCommentDetails.Comments)
                {
                    this.SelectedComment = item;
                }
            }
            else
            {
                await System.Threading.Tasks.Task.Delay(1000);
                MessageBoxResult msgResult = MessageBox.Show(Constants.NETWORK_ERROR, Constants.NETWORK_ERROR_TITLE, MessageBoxButton.OKCancel);
                if (msgResult == MessageBoxResult.OK)
                {
                    await GetCommentDetail();
                }
                else
                {
                    Application.Current.Terminate();
                }
            }
        }
        catch (Exception)
        {
            BaseViewModel.ShowErrorMessage();
        }
    }
    public async Task GetReplyList()
    {
        try
        {
            // LoaderForReplyVisibility = Visibility.Visible; // add this later, it think it should control display of usercontrol for replying
            string Api_Url = string.Format(Constants.LoadCommentReplies_API, BaseViewModel.SelectedCommentID) + "?timestamp" + DateTime.Now.ToString();
            if (BaseViewModel.HelperClass.IsInternet())
            {
                var response = await BaseViewModel.HelperClass.Get(Api_Url);
                this.ReplyDetailsData = JSONHelper.DeserializeFromJson<ReplyDetails>(response);
                if (ReplyDetailsData.Error.ToLower() == "none")
                {
                    this.ReplyList = this.ReplyDetailsData.details.replies.ToObservableCollection();
                    LoaderForReplyVisibility = Visibility.Collapsed;
                }
            }
            else
            {
                await System.Threading.Tasks.Task.Delay(1000);
                MessageBoxResult msgResult = MessageBox.Show(Constants.NETWORK_ERROR, Constants.NETWORK_ERROR_TITLE, MessageBoxButton.OKCancel);
                if (msgResult == MessageBoxResult.OK)
                {
                    await GetReplyList();
                }
                else
                {
                    Application.Current.Terminate();
                }
            }
        }
        catch (Exception)
        {
            BaseViewModel.ShowErrorMessage();
        }
    }
    public async Task GetVideoDetail()
    {
        try
        {
            string Api_Url = string.Format(Constants.VideoDetail_API, BaseViewModel.SelectedVideoID) + "?timestamp" + DateTime.Now.ToString();
            if (BaseViewModel.HelperClass.IsInternet())
            {
                var response = await BaseViewModel.HelperClass.Get(Api_Url);
                this.VideoDetailData = JSONHelper.DeserializeFromJson<CeFlix.Entities.VideoDetails>(response);
                if (VideoDetailData.Error.ToLower() == "none")
                {
                    this.VideoDetail = this.VideoDetailData.Details.FirstOrDefault();
                    //  this.GetVideoViews();
                }
            }
            else
            {
                await System.Threading.Tasks.Task.Delay(1000);
                MessageBoxResult msgResult = MessageBox.Show(Constants.NETWORK_ERROR, Constants.NETWORK_ERROR_TITLE, MessageBoxButton.OKCancel);
                if (msgResult == MessageBoxResult.OK)
                {
                    await GetVideoDetail();
                }
                else
                {
                    Application.Current.Terminate();
                }
            }
        }
        catch (Exception)
        {
            BaseViewModel.ShowErrorMessage();
        }
    }
    private async void UserSubmitReplyCommandClick()
    {
        try
        {
            if (BaseViewModel.HelperClass.IsInternet())
            {
                if (!string.IsNullOrEmpty(this.Message))
                {

                    HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(Constants.Reply_API);
                    webRequest.Method = "POST";
                    webRequest.UserAgent = "immtv.loveworldapis.com";
                    webRequest.ContentType = "application/x-www-form-urlencoded";
                    webRequest.BeginGetRequestStream(new AsyncCallback(GetRequestSubmitReplyStreamCallback), webRequest);
                }
                else
                {
                    MessageBox.Show("First Enter Reply");
                }
            }
            else
            {
                await System.Threading.Tasks.Task.Delay(1000);
                MessageBoxResult msgResult = MessageBox.Show(Constants.NETWORK_ERROR, Constants.NETWORK_ERROR_TITLE, MessageBoxButton.OKCancel);
                if (msgResult == MessageBoxResult.OK)
                {
                    UserSubmitReplyCommandClick();
                }
                else
                {
                    Application.Current.Terminate();
                }
            }
        }
        catch (Exception)
        {
            BaseViewModel.ShowErrorMessage();
        }
    }

    // settle down to analyze this method because it's the body of the POST for posting a reply
    void GetRequestSubmitReplyStreamCallback(IAsyncResult callbackResult)
    {
        try
        {
            string requestBody = "";
            HttpWebRequest webRequest = (HttpWebRequest)callbackResult.AsyncState;
            Stream postStream = webRequest.EndGetRequestStream(callbackResult);
            // requestBody = "email=" + BaseViewModel.UserEmailId + "&reply=" + Message + "&video_id=" + BaseViewModel.SelectedVideoID;
            requestBody = "commentID=" + BaseViewModel.SelectedCommentID + "&comment=" + Message + "&email=" + BaseViewModel.UserEmailId;

            byte[] byteArray = Encoding.UTF8.GetBytes(requestBody);
            postStream.Write(byteArray, 0, byteArray.Length);
            postStream.Close();
            webRequest.BeginGetResponse(new AsyncCallback(GetResponseUserSubmitReplyStreamCallback), webRequest);
        }
        catch (Exception)
        {
            BaseViewModel.ShowErrorMessage();
        }
    }

    // and this too
    void GetResponseUserSubmitReplyStreamCallback(IAsyncResult calldatabackResult)
    {
        try
        {
            HttpWebRequest request = (HttpWebRequest)calldatabackResult.AsyncState;
            HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(calldatabackResult);
            using (StreamReader httpWebStreamReader = new StreamReader(response.GetResponseStream()))
            {
                string result = httpWebStreamReader.ReadToEnd();
                UserStatusData = JSONHelper.DeserializeFromJson<CeFlix.Entities.UserStatusData>(result);
            }
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                if (UserStatusData.status == "OK")
                {
                    //  this.GetReplyList();
                    this.Message = string.Empty;
                    MessageBox.Show("Reply Added Successfully");
                    RepliesViewModel repliesViewModel = RepliesViewModel.GetSingleInstance();
                    ReplyListControlVisibility = Visibility.Collapsed;
                    repliesViewModel.GetReplyList();
                    ReplyListControlVisibility = Visibility.Visible;
                }
            });
        }
        catch (Exception)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                BaseViewModel.ShowErrorMessage();
            });
        }
    }


    #endregion
}

}

和BaseViewModel, RepliesViewModel继承自

 public event PropertyChangedEventHandler PropertyChanged;
    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
    {
        if (object.Equals(storage, value)) return false;
        storage = value;
        this.OnPropertyChanged(propertyName);
        return true;
    }

我已经尝试了一些事情,比如调用ListBox. items . clear(),这返回了一个调试器错误,我尝试了ListBox。ItemsSource = null并再次绑定它,仍然不起作用。我需要做什么来触发刷新并立即更新列表框中显示的数据?

要解决这个问题,只需在构造函数中设置数据上下文即可:

    public MyPageConstructor() // Your page constructor
    {
        this.DataContext = new RepliesViewModel(); // Or any other way how you create your view model
    }
    protected async override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        string parameter = this.NavigationContext.QueryString["parameter"];
        BaseViewModel.SelectedCommentID = parameter;

    }
    private async void ContentPanel_Loaded(object sender, RoutedEventArgs e)
    {
        await repliesViewModel.GetReplyList();
        //this.DataContext = this.repliesViewModel;
        //lbxReplies.ItemsSource = null; *removed*
        //lbxReplies.ItemsSource = repliesViewModel.ReplyList;
    }

并在您的ListBox上绑定ItemsSource:

<ListBox x:Name="lbxReplies" 
         ItemsSource="{Binding ReplyList}"
         Margin="0,0,-12,0" 
         >

编辑:我想你可能有一个错误在你的GetResponseUserSubmitReplyStreamCallback方法:

RepliesViewModel repliesViewModel = RepliesViewModel.GetSingleInstance();
repliesViewModel.GetReplyList();

如果你的RepliesViewModel.GetSingleInstance()方法创建了一个new实例,那么这段代码将没有任何用处。

如果GetResponseUserSubmitReplyStreamCallback方法在你的页面类中,那么你可能只想调用

repliesViewModel.GetReplyList();

您需要创建一种继承ObservableCollection的新列表(看起来您已经这样做了):

public class MyItems:ObservableCollection<Item>
{
}

你还需要MyItemsInstance符合INotifyPropertyChanged "pattern"

public class YourViewModelClass:INotifyPropertyChanged
{ 
  public event PropertyChangedEventHandler PropertyChanged;
  public MyItems MyItemsInstance
  {
    get
    {
        return this.customerNameValue;
    }
    set
    {
        if (value != this.customerNameValue)
        {
            this.customerNameValue = value;
            NotifyPropertyChanged();
        }
    }
  }
  private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
  {
      if (PropertyChanged != null)
      {
          PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
  }
}

然后你可以调用这个服务来填充你的列表实例。

如果您以正确的方式使用MVVM,则此操作有效。在XAML中,你需要绑定列表源和列表实例,我可以在代码中看到这部分。看看ItemsSource属性

<ListBox x:Name="lbxReplies" ItemsSource="{Binding MyItemsInstanceInModel}"
             Margin="0,0,-12,0" 
             >
<!--All other stuff-->
</ListBox>

如果绑定是OK的,一旦你修改了MyItemsInstanceInModel的内容,或者即使你分配了一个新的实例,UI应该自己刷新。

  1. 在清空列表框(lbxReplies. items . clear()或lbxReplies. clear())后添加lbxReplies. items . refresh()。ItemsSource = null).
  2. 因为,lisReplyList被绑定到lbxReplies。因此,调用ReplyList.Clear()而不是lbxReplies. items . clear()或lbxReplies。ItemsSource = null.

最新更新