WPF:在 UserControl 的构造函数中加载数据会破坏设计器

Posted

技术标签:

【中文标题】WPF:在 UserControl 的构造函数中加载数据会破坏设计器【英文标题】:WPF: Loading data in the constructor of a UserControl breaks the Designer 【发布时间】:2010-10-08 22:17:28 【问题描述】:

我有一个带有用户控件的主窗口。在用户控件的默认构造函数中添加代码时,设计器停止显示主窗口。它给出了一条信息:

加载问题

文档包含在加载设计器之前必须修复的错误。 修复错误后重新加载设计器。

重新加载设计器

这是为什么?

这是我在构造函数中的代码:

using (var context = new Data.TVShowDataContext())

    var list = from show in context.Shows
               select show;

    listShow.ItemsSource = list;

如果我不能使用构造函数来填充 gui 数据,我应该什么时候做呢?用绑定来做这件事会更好吗?有什么建议吗?

【问题讨论】:

错误列表显示此消息:“无法创建 BrowseShow 类型的实例”。设计区域显示问题中引用的消息。 我测试并更新了我的答案 【参考方案1】:

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;
      

【讨论】:

我将其标记为答案,尽管我现在已经学会了 MVVM 的乐趣并且我的控件中不再有任何代码:-)【参考方案2】:

我个人会为我的数据源使用可观察的集合。那里有很多例子,但基本上你的代码看起来像这样。我没有测试过这段代码。如果有任何问题,请添加一些 cmets。

这里有两个要点。一,除非您不在设计模式下,否则不要加载任何数据(如果您需要设计支持,您可以放置​​和 else 语句并加载存根 POCO 数据)。第二,你应该在一个单独的线程上加载你的数据,然后是你的 UI 线程。

更新

代码有几个更新。我将(新线程)更改为使用 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) 通过检查“DesignMode”的默认构造函数或; 2) 拥有一个用于“实时”数据的更复杂的构造函数和一个不进行数据库调用的默认构造函数。 时间太少,要学的东西太多... :-) 我对新的 Thread(....) 行有疑问。 “错误 2 委托 'System.Threading.ParameterizedThreadStart' 不采用 '0' 参数”你有解决方案吗? 我对在默认构造函数中启动一个新线程持谨慎态度。你能把它移到更“复杂”的构造函数上吗?

以上是关于WPF:在 UserControl 的构造函数中加载数据会破坏设计器的主要内容,如果未能解决你的问题,请参考以下文章

无法在 WPF 项目中加载 DLL

当我们单击 DataGrid 行时,在 wpf 功能区窗口中加载另一个用户控件

WPF后台如何获得前台XAML中对象

在WPF中UserControl

WPF中UserControl控件的关闭

在 UserControl WPF MVVM caliburn 内的 UserControl 之间切换