繁体   English   中英

从Web请求返回值后,WP7中未填充ListBox

[英]ListBox not populated in WP7 after values return from web request

我正在尝试从头开始为WP7构建一个简单的应用程序。 MainPage.xaml中的列表框如下所示:

<Grid x:Name="ContentPanel" Grid.Row="1" >
    <ListBox x:Name="MainListBox" ItemsSource="{Binding result}" SelectionChanged="MainListBox_SelectionChanged">
        <ListBox.ItemTemplate>
           <DataTemplate>
               <StackPanel>
                   <TextBlock Text="{Binding name}" TextWrapping="Wrap" />
                   <TextBlock Text="{Binding description}" TextWrapping="Wrap" />
               </StackPanel>
           </DataTemplate>
        </ListBox.ItemTemplate>
   </ListBox>
</Grid>

为了填充结果及其元素,名称和描述,我需要从Web服务器获取值,该Web服务器使用json响应我发送的get请求。 由于我需要对服务器进行不同的调用以响应不同的json对象,因此我为每个服务器维护了不同的.cs文件,与mainpage.cs无关(我仅在其中初始化,定义MainPage_Loaded和MainListBox_SelectionChanged)。 所有数据都在单个.cs文件中提取和处理。 现在的问题是,当我进行httpwebrequest并检索到响应时,UI早于此加载。 据我从其他帖子中了解到,BeginGetResponse成为后台进程,并且加载了UI以使其保持响应状态。 因此,总结一下,在Web请求与服务器中的数据一起返回之前,由于未填充数据,因此UI被加载为空白。 现在,由于我不在MainPage.cs中,因此无法使用Dispatcher进行填充,因此无法直接访问列表框。 我也尝试了回调,但没有成功。 请帮忙

MainPage.cs:

public partial class MainPage : PhoneApplicationPage
{
    // Constructor
    public MainPage()
    {
        InitializeComponent();
        this.Loaded +=new RoutedEventHandler(MainPage_Loaded);
    }

    private void MainListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (MainListBox.SelectedIndex == -1)
            return;

        NavigationService.Navigate(new Uri("/DetailsPage.xaml?selectedItem=" + MainListBox.SelectedIndex, UriKind.Relative));

        MainListBox.SelectedIndex = -1;
    }

    // Load data for the ViewModel Items
    private void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        if (!App.ViewModel.IsDataLoaded)            
            App.ViewModel.LoadData();            
    }
}

LoadData()本质上初始化请求参数,准备URI并将HTTP请求发送到另一个类(executeRequest.cs文件)中的另一个函数,该类获取响应并将请求处理为可以映射到的对象:

public void decodeJson<E>(HttpWebRequest request)
    {
        request.Method = "GET";
        var reqresult = (IAsyncResult)request.BeginGetResponse(ResponseCallback<E>, request);
    }

    public void ResponseCallback<E>(IAsyncResult reqresult)
    {
        var request = (HttpWebRequest)reqresult.AsyncState;
        var response = (HttpWebResponse)request.EndGetResponse(reqresult);

        if (response.StatusCode == HttpStatusCode.OK)
        {
            var stream = response.GetResponseStream();
            var reader = new StreamReader(stream);
            var contents = reader.ReadToEnd();
            if (contents.ToString().StartsWith("{\"jsonrpc"))
            {
                using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(contents)))
                {
                    Type typeofe = typeof(E);
                    var deserializer = new DataContractJsonSerializer(typeof(E));
                    E element = (E)deserializer.ReadObject(ms);
                    populateResult<E>(element);
                }
            }
        }
    }

在populateResult中,我试图填充UI。 但是,当控件进入BeginGetResponse时,由于列表框,MainListBox无法访问,因此我的UI已填充并在populateResult中,我无法使用分派器用新数据刷新 UI

为了提供更多信息,结果是一个类的ObservableCollection,该类包含来自json的不同属性

populateResult非常简单:

private void processResult<E>(E element)
    {
        //Checking for the type of result so that I can map
        string typeis = typeof(E).ToString();
        if (typeis.EndsWith("MyViewModel")
            {
              App.ViewModel.result = (element as MyViewModel).result;
              ???
            }
    }

也许我应该承认这个(???)是我被困住的地方。 结果集合已更新,但不在UI中。 UI仍然是空白,我无法从populateRsult访问MainListBox进行更新。 希望清楚。 否则请告诉我

出于礼貌,我还提供MyViewModel和SubViewModel

MyViewModel:

public class MyViewModel : INotifyPropertyChanged
{
    public MyViewModel()
    {            
        this.result = new ObservableCollection<SubViewModel>();
    }        
    public ObservableCollection<SubViewModel> result { get; set; }
    private string _sampleProperty = "Sample Runtime Property Value";
    public string SampleProperty
    {
        get
        {
            return _sampleProperty;
        }
        set
        {
            _sampleProperty = value;
            NotifyPropertyChanged("SampleProperty");
        }
    }

    public bool IsDataLoaded
    {
        get;
        private set;
    }
    public void LoadData()
    {
        //Initialize all the parameters
        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(string.Format
            (uri with parameters);            
        request.Method = "GET";
        //call the decide json to get the reponse and parse it
        executeRequest execReq = new executeRequest();
        execReq.decodeJson<MyViewModel>(request);

        this.IsDataLoaded = true;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String propertyName)
    {
        if (null != PropertyChanged)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

子视图模型:

public class SubViewModel : INotifyPropertyChanged 
{
    private string _name;
    public string name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
            NotifyPropertyChanged("name");
        }
    }

    private string _description;
    public string description
    {
        get
        {
            return _description;
        }
        set
        {
            _description = value;
            NotifyPropertyChanged("description");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String propertyName) 
    {
        if (null != PropertyChanged) 
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

我看不到有关如何将内容绑定到列表框的任何信息。 你有一个结合result在XAML中,但并未显示,它实际上是什么声明。 如果它是一个可观察的集合,则populateResult方法应该非常简单,只需使用新数据更新可观察的集合的内容即可。

如果要在填充结果中重新创建可观察的集合,而不仅仅是更改其内容,那可能就是您的问题。

更新:

最大的问题(从更新后的代码可以看出)是,在设置result时,您的视图模型没有引发属性更改。 因此,您需要执行以下两项操作之一:

a)在result上添加属性更改支持,例如视图模型类对SampleProperty ,以便在对其进行修改时,绑定可以看到更改:

private ObservableCollection<SubViewModel> _result = new ObservableCollection<SubViewModel>();
public ObservableCollection Result    
{
    get
    {
        return _result;
    }        
    set
    {
        _result = value;
        NotifyPropertyChanged("Result");
    }
}

// -- elsewhere --
private void processResult<E>(E element)    
{        
    // (why were you using the type **name** to check the 
    // type of the result instead of just using `as`?)
    var model = element as MyViewModel;
    if (model != null)
    {              
        App.ViewModel.Result = model.result;              
    }    
}

b)否则您不需要设置 result ,而是修改其内容,因为它已经是一个可观察的集合:

private void processResult<E>(E element)    
{        
    var model = element as MyViewModel;
    if (model != null)
    {              
        // result is an ObservableCollection, so just modify its contents.  
        // anything bound to it will see the changes via collection change notifications
        App.ViewModel.result.ClearItems();
        foreach (var x in model.result)
            App.ViewModel.result.Add(x);
    }    
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM