ListBox не заполняется в WP7 после возврата значений из веб-запроса - PullRequest
0 голосов
/ 05 января 2011

Я пытаюсь создать простое приложение для 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>

Чтобы заполнить результат и его элементы, имя и описание, мне нужно получить значения с веб-сервера, который отвечает с помощью json для получениязапрос отправляю.Так как мне нужно делать разные вызовы на сервер, которые отвечают разными объектами json, я поддерживаю разные файлы .cs для каждого, независимо от mainpage.cs (где я только инициализирую, определяю MainPage_Loaded и MainListBox_SelectionChanged).Все данные выбираются и обрабатываются в отдельных файлах .cs.Теперь проблема в том, что когда я делаю httpwebrequest и получаю ответ, пользовательский интерфейс загружается задолго до этого.Как я понял из других постов, BeginGetResponse становится фоновым процессом, и пользовательский интерфейс загружается, чтобы сохранить его отзывчивость.Таким образом, чтобы подвести итог перед возвратом веб-запроса с данными с сервера, пользовательский интерфейс загружается как пустой, так как данные не заполняются.Теперь я не могу использовать Dispatcher для заполнения, поскольку я не нахожусь в MainPage.cs и поэтому не могу получить прямой доступ к списку.Я также пробовал перезвонить, но безуспешно.Пожалуйста, помогите

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 я пытаюсь заполнить пользовательский интерфейс.Но к тому времени, когда элемент управления входит в BeginGetResponse, мой пользовательский интерфейс заполнен и в populateResult, так как список не доступен, MainListBox недоступен. Я не могу использовать диспетчер для обновления пользовательского интерфейса с новыми данными

.более подробная информация, результатом является 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;
              ???
            }
    }

Вероятно, я должен признать это (???), где я застрял.Коллекция результатов обновляется, но не в пользовательском интерфейсе.Пользовательский интерфейс все еще пуст, и я не могу получить доступ к MainListBox из populateRsult для обновления.Надеюсь, это понятно.В противном случае, пожалуйста, скажите мне

С учтивостью позвольте мне также предоставить 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));
        }
    }
}

SubviewModel:

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));
        }
    }
}

1 Ответ

1 голос
/ 05 января 2011

Я не вижу ничего о том, как вы связываете что-то со своим списком.у вас есть привязка к result в вашем xaml, но вы не показываете, что это на самом деле.Если это наблюдаемая коллекция, ваш метод populateResult должен быть довольно тривиальным, просто обновляя содержимое наблюдаемой коллекции новыми данными.

Если вы воссоздаете наблюдаемую коллекцию в результате заполнения, а не просто меняете ее содержимое, это может стать вашей проблемой.

update:

Самая большая проблема (насколько я могу судить по вашему обновленному коду) заключается в том, что ваша модель представления не вызывает изменения свойства при установке 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);
    }    
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...