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:
我有一个带有usercontrol的主窗口。在usercontrol的默认构造函数中添加代码时,设计器停止显示主窗口。它给出了一个信息:
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?
如果我不能使用构造函数来填充gui数据,我应该什么时候做呢?用绑定做这件事会更好吗?任何sugestions怎么样?
2 个解决方案
#1
13
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.
WPF设计器将在显示子元素时执行构造函数。我的猜测是你在构造函数中有代码在设计时抛出一个异常,可能是因为它使用了一个仅在运行时可用的对象。解决方案是使用检查来围绕构造函数逻辑,以防止它在设计器中显示时执行。
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
using (var context = new Data.TVShowDataContext())
{
var list = from show in context.Shows
select show;
listShow.ItemsSource = list;
}
}
#2
1
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.
这里有两个要点。一,除非你没有处于设计模式,否则不要加载任何数据,(如果你需要设计支持,你可以把if和else语句加载存根POCO数据)。二,你应该在一个单独的线程上加载你的数据然后你的UI线程。
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
代码有几处更新。我将(新线程)更改为使用QueueUserWorkItem,我更改了AddItems方法,因为ObservableCollection不支持AddRange,我更改了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);
}
}
}
#1
13
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.
WPF设计器将在显示子元素时执行构造函数。我的猜测是你在构造函数中有代码在设计时抛出一个异常,可能是因为它使用了一个仅在运行时可用的对象。解决方案是使用检查来围绕构造函数逻辑,以防止它在设计器中显示时执行。
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
using (var context = new Data.TVShowDataContext())
{
var list = from show in context.Shows
select show;
listShow.ItemsSource = list;
}
}
#2
1
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.
这里有两个要点。一,除非你没有处于设计模式,否则不要加载任何数据,(如果你需要设计支持,你可以把if和else语句加载存根POCO数据)。二,你应该在一个单独的线程上加载你的数据然后你的UI线程。
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
代码有几处更新。我将(新线程)更改为使用QueueUserWorkItem,我更改了AddItems方法,因为ObservableCollection不支持AddRange,我更改了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);
}
}
}