views:

1899

answers:

2

I have a main window with a usercontrol. When adding code in the default constructor of the usercontrol, the designer stops showing the main window. It gives a message:

Problem loading

The document contains errors that must be fixed before the designer can be loaded.
Reload the designer after you have fixed the errors.

Reload the designer

Why is this?

This is the code that I have in the constructor:

using (var context = new Data.TVShowDataContext())
{
    var list = from show in context.Shows
               select show;

    listShow.ItemsSource = list;
}

If I can't use the constructor to fill gui with data, when should I else do it? Would it be better to do this with binding? Any sugestions how?

+1  A: 

I would personally use an observable collection for my datasource. There are lots of examples out there, but essentially your code would look something like this. I haven't tested this code. Add some comments if you have any problems.

There are two main points here. One, don't load any data unless your not in design mode, (you could put and else statement and load stub POCO data if you need design support). Two, you should load your data on a seperate thread then your UI thread.

Updated

There was a couple of updates to the code. I changed the (new Thread) to using QueueUserWorkItem, I changed the AddItems method because ObservableCollection doesn't support AddRange, and I changed the spelling on IEnumerable

public class TvShowsDataSource
{
    public ObservableCollection<Show> Shows { get; set; }

    private void AddItems(IEnumerable<Show> shows)
    {
            foreach(var show in shows)
                   Shows.Add(show);
    }

    public void LoadShowsAsync(Dispatcher dispatcher)
    {
            ThreadPool.QueueUserWorkItem((state) =>
                   LoadShows(dispatcher));
    }

    private void LoadShows(Dispatcher dispatcher)
    {
     if (dispatcher == null)
      throw new ArgumentNullException("dispatcher");

     using (var context = new Data.TVShowDataContext())
     {
         var list = from show in context.Shows
                    select show;

         dispatcher.Invoke(AddItems(list));
     }
    }
}

public class UserControl1
{
    private readonly TvShowsDataSource tvShowsDataSource;

    public UserControl1() : this(new TvShowsDataSource()) {}

    public UserControl1(TvShowsDataSource tvShowsDataSource )
    {
     InitializeComponent();
     this.tvShowsDataSource = tvShowsDataSource;
     listShow.ItemsSource = tvShowsDataSource.Shows;
     this.Loaded += UserControl1_Loaded;
    }

    public void UserControl1_Loaded(object sender, RoutedEventArgs e)
    {
     if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
     {
      tvShowsDataSource.LoadShowsAsync(this.Dispatcher);
     }
    }
}
bendewey
Simple corollary is that if you have to load data, do it either 1) By checking in your default constructor for "DesignMode" or; 2) Having a more complex constructor that you use for "live" data and a default constructor that makes no database calls.
KP Adrian
So little time, so much to learn... :-) I have problems with the new Thread(....)-line. "Error 2 Delegate 'System.Threading.ParameterizedThreadStart' does not take '0' arguments" Do you have a solution for that?
Vegar
I'd be leery of starting a new thread in a default constructor. Can you move that to the more "complex" constructor?
KP Adrian
@KP I'm actually starting the thread on the Loaded Event
bendewey
+2  A: 

The WPF designer will execute the constructor on child elements when displaying them. My guess is that you've got code in the constructor that throws an exception at design-time, probably because it's using an object that's only available at run-time. A solution would be to surround your constructor logic with a check to prevent it from executing while it's being displayed in the designer.

if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
  using (var context = new Data.TVShowDataContext())
  {
    var list = from show in context.Shows
               select show;

    listShow.ItemsSource = list;
  }    
}
The Reddest