【问题标题】:How to set the datacontext of a user control如何设置用户控件的数据上下文
【发布时间】:2010-05-17 17:51:26
【问题描述】:

我正在使用 MVVm 工具包在 WPF 中编写应用程序,但在连接视图模型和视图时遇到问题。

模型是使用 ado.net 实体框架创建的。

视图模型:

public class CustomerViewModel
    {
        private Models.Customer customer;
        //constructor
        private ObservableCollection<Models.Customer> _customer = new ObservableCollection<Models.Customer>();
        public ObservableCollection<Models.Customer> AllCustomers
        {
            get { return _customer; }

        }
        private Models.Customer _selectedItem;
        public Models.Customer SelectedItem
        {
            get { return _selectedItem; }

        }
        public void LoadCustomers()
        {
            List<Models.Customer> list = DataAccessLayer.getcustomers();
            foreach (Models.Customer customer in list)
            {
                this._customer.Add(customer);
            }
            }
        }

还有视图(目前没有代码):

<UserControl x:Class="Customers.Customer"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             xmlns:vm ="clr-namespace:Customers.ViewModels"
             d:DesignHeight="300" d:DesignWidth="300"
             xmlns:toolkit="http://schemas.microsoft.com/wpf/2008/toolkit" >

    <Grid>
        <toolkit:DataGrid ItemsSource="{Binding AllCustomers}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" AutoGenerateColumns="True">

        </toolkit:DataGrid>

        <toolkit:DataGrid ItemsSource="{Binding SelectedItem.Orders}">

        </toolkit:DataGrid>



    </Grid>
</UserControl>

和dataaccesslayer类:

 class DataAccessLayer
    {
        public List<Customer> customers = new List<Customer>();

        public static List<Customer> getcustomers()
        {
            entities db = new entities();

            var customers = from c in db.Customer.Include("Orders")
                           select c;
            return customers.ToList();
        }


    }

问题是没有数据显示仅仅因为数据上下文没有设置。我试图在代码隐藏中做到这一点,但没有奏效。无论如何,我宁愿在 xaml 文件中执行此操作。另一个问题是 SelectedItem 绑定 - 代码从未使用过。

【问题讨论】:

  • 在您的代码中,您的视图模型上有一个 AllCustomers 属性,但您绑定到客户。
  • 我正在稍微清理代码并打错了字。工作代码中的绑定当然是正确的。

标签: wpf mvvm data-binding


【解决方案1】:

由于这是使用 MVVM 范例,我将在视图的构造函数中实例化您的 ViewModel。我的视图/视图模型通常遵循以下事件序列:

  1. 视图已实例化
  2. 查看构造函数实例 ViewModel
  3. ViewModel 初始化
  4. ViewModel 运行数据获取程序(单独线程)
  5. ViewModel 调用 OnPropertyChanged("") 来提醒 View 发生了一些变化;检查一切

我的 ViewModel 是从 XAML 代码隐藏中实例化的(抱歉,这是在 VB.NET 中,还没有足够好地学习 C# 以信任自己):

Public Sub New()
    MyBase.New()
    Me.DataContext = New EditShipmentViewModel(Me) 'pass the view in to set as a View variable
    Me.InitializeComponent()
End Sub

最初我希望有类似的东西

<UserControl>
    <UserControl.DataContext>
        <Local:EditShipmentViewModel>
    </UserControl.DataContext>
</UserControl>

但这并没有如我所愿。

希望能有所帮助。

【讨论】:

  • 这与 MVVM 正好相反。
  • @EdPlunkett 完全欢迎您发表答案。
  • 这是 WPF 中最常见的反模式之一。您不应该鼓励初学者使用会给他们带来麻烦和挫败感的反模式。
【解决方案2】:

this 是你要找的吗?

【讨论】:

  • 是和不是。我需要以某种方式调用getcustomers() 方法。我应该在视图模型构造函数中这样做吗?好像不太好。
  • 就我个人而言,我会在构造函数中调用 ViewModel 的 getcustomers()。你觉得它有什么不好的地方?当视图呈现时,它将创建一个新的 ViewModel 实例,此时您希望检索数据,因此构造函数这样做是有意义的。
  • Resources中的xaml构造怎么样?
  • 在 XAML 中声明对象的唯一主要问题是,在 VM 构建期间引发的任何错误都将被 XAML 解析错误所吞噬。我们已经关闭使用像 MEF 这样的 DI 在加载时将 VM 注入 View 的 DataContext。 OnLoad 可以触发多次,因此请确保使用 _isLoaded 字段或类似字段将其短路。
  • 是的,这肯定是使用 DI 的更好解决方案。不错的评论!
【解决方案3】:

我以与观察 Blend4 相同的方式设置视图模型数据上下文。也就是说,如果我的视图模型被称为 MainViewModel,我会在视图中引用它,如下所示:

 <UserControl.Resources>
    <local:MainViewModel x:Key="MainViewModelDataSource" />
 </UserControl.Resources>

 <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource MainViewModelDataSource}}">
    ...view xaml stuff

 </Grid>

另外,如果您在视图模型的构造函数中从数据库加载数据,请不要忘记在其周围添加一个辅助方法,例如:

  if (!DesignerProperties.GetIsInDesignMode(new DependencyObject()))
        {
             myCollection = new ObservableCollection<Blah>(something);
        }

这样 Visual Studio/Blend4 在尝试从 Designer 中的数据库连接检索数据时不会崩溃。我个人经常在构造函数中加载数据,只是因为我马上需要它,并且从启动时就将其缓存在内存中。

:)

【讨论】:

    猜你喜欢
    • 2012-12-16
    • 2012-04-01
    • 2019-11-16
    • 1970-01-01
    • 2013-04-15
    • 1970-01-01
    • 2013-12-27
    • 2012-11-07
    • 1970-01-01
    相关资源
    最近更新 更多