Silverlight 4 + WCF с MVVM: коллекция по какой-то причине не заполняется - PullRequest
0 голосов
/ 23 июля 2011

Позвольте мне сначала показать код.

Функция сервисного контракта WCF:

   public List<VenueData> GetVenues()
    {
        List<VenueData> listOfVenues = new List<VenueData>();

        string connString = @"....";

        DataContext dc = new DataContext(connString);
        Table<VenueData> venues = dc.GetTable<VenueData>();

        listOfVenues = (from v in venues
                       select v).ToList();

        return listOfVenues;
    }

VenueViewModel.cs

public class VenueViewModel : ViewModelBase
{
    private VenueData _venue;
    private ObservableCollection<VenueData> _venues = new ObservableCollection<VenueData>();        

    public VenueData Venue
    {
        get
        {
            return _venue;
        }
        set
        {
            if (_venue != value)
            {
                _venue = value;
                OnNotifyPropertyChanged("Venue");
            }
        }
    }

    public ObservableCollection<VenueData> Venues
    {
        get
        {
            return _venues;
        }
        set
        {
            if (_venues != value)
            {
                _venues = value;
                OnNotifyPropertyChanged("Venues");
            }
        }
    }

    public void GetAllVenues()
    {

        TicketOrderWcfClient toClient = new TicketOrderWcfClient();
        toClient.GetVenuesCompleted += new EventHandler<GetVenuesCompletedEventArgs>(toClient_GetVenuesCompleted);
        toClient.GetVenuesAsync();            
    }

    void toClient_GetVenuesCompleted(object sender, GetVenuesCompletedEventArgs e)
    {
        if (e.Error == null)
            Venues = e.Result;
    }
}

MainPage.xaml (просмотреть)

   public MainPage()
    {
        InitializeComponent();
        Loaded += new RoutedEventHandler(MainPage_Loaded);
    }

    void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        VenueViewModel vvm = new VenueViewModel();
        vvm.GetAllVenues();

        MessageBox.Show(vvm.Venues.Count.ToString());

    }

Ну, это большая часть кода. Проблема состоит в том, что в событии MainPage_Loaded vvm.GetAllVenues () не будет заполнять коллекцию объектов ObservableCollection. MessageBox покажет 0. Я проверил, что сервис wcf хорош, также fiddler показал, что мыло в порядке. Также, если я вызову службу wcf в событии MainPage_Loaded, то это будет работать. Смотрите ниже:

    void MainPage_Loaded(object sender, RoutedEventArgs e)
    {

        TicketOrderWcfClient toClient = new TicketOrderWcfClient();
        toClient.GetVenuesCompleted += new EventHandler<GetVenuesCompletedEventArgs>(toClient_GetVenuesCompleted);
        toClient.GetVenuesAsync();  
    }


    void toClient_GetVenuesCompleted(object sender, GetVenuesCompletedEventArgs e)
    {
        if(e.Error == null)
        {
            VenueViewModel vvm = new VenueViewModel();
            vvm.Venues = e.Result;
            MessageBox.Show(vvm.Venues.Count.ToString());
        }
    }

На этот раз MessageBox покажет 3, что хорошо, потому что в БД есть 3 записи. Таким образом, похоже, что существует проблема между View и ViewModel. Я подозреваю, что мне здесь не хватает довольно простой вещи. Также обратите внимание, что я знаю, что это не настоящий MVVM, но я должен выполнить эту программу таким образом. Я надеюсь, что мое объяснение понятно, спасибо за вашу помощь.

Ответы [ 2 ]

0 голосов
/ 23 июля 2011

В вашем первом подходе, который не работает, поток кода:

MessageBox.Show(vvm.Venues.Count.ToString());

не связано с завершением вашего асинхронного вызова метода WCF! Другими словами, вы показываете mbox, но не уверены, что асинхронный вызов завершен.

Конечно, вы назначили делегата для события GetVenuesCompleted, но вызов toClient.GetVenuesAsync () является асинхронным вызовом, что означает, что при вызове он не ждет результата (завершения). Поэтому, когда вы звоните:

vvm.GetAllVenues();

Тогда

MessageBox.Show(vvm.Venues.Count.ToString());

вызывается быстрее, чем ваш делегат toClient_GetVenuesCompleted.

Ваш второй подход работает, потому что вы отображаете окно сообщения после завершения асинхронного метода (в вашем обратном вызове GetVenues).

По моему мнению, вы можете исправить это, например, добавив новое событие GetAllVenuesCompleted в VenueViewModel, которое будет запущено в конце делегата toClient_GetVenuesCompleted. Другими словами, я бы пропустил это событие дальше. Кроме того, я хотел бы добавить комментарий, что GetAllVenues является асинхронным методом.

0 голосов
/ 23 июля 2011

Полагаю, проблема в том, что вы создаете новую виртуальную машину.

void toClient_GetVenuesCompleted(object sender, GetVenuesCompletedEventArgs e)
{
    if(e.Error == null)
    {
        VenueViewModel vvm = new VenueViewModel();
        vvm.Venues = e.Result;
        MessageBox.Show(vvm.Venues.Count.ToString());
    }
}

Я думаю, что этот код работает. Вы создаете новую VenueViewModel, заполняете ее данными, и это все. Эта виртуальная машина никогда не используется снова. Те же правила для образца MainPage.xaml.
Вы должны создать глобальную переменную VenuViewModel в конструкторе / загруженном обработчике и вызвать ее GetAllVenues в событии Loaded

...