在WPF中使用XAML设置DataContext

76

我有以下代码:

MainWindow.xaml

<Window x:Class="SampleApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{Binding Employee}">
    <Grid>       
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="200" />
        </Grid.ColumnDefinitions>

        <Label Grid.Row="0" Grid.Column="0" Content="ID:"/>
        <Label Grid.Row="1" Grid.Column="0" Content="Name:"/>
        <TextBox Grid.Column="1" Grid.Row="0" Margin="3" Text="{Binding EmpID}" />
        <TextBox Grid.Column="1" Grid.Row="1" Margin="3" Text="{Binding EmpName}" /> 
    </Grid>
</Window>

员工.cs

namespace SampleApplication
{
    public class Employee
    {
        public Employee()
        {
            EmployeeDetails employeeDetails = new EmployeeDetails();
            employeeDetails.EmpID = 123;
            employeeDetails.EmpName = "ABC";
        }
    }

    public class EmployeeDetails
    {
        private int empID;
        public int EmpID
        {
            get
            {
                return empID;
            }
            set
            {
                empID = value;
            }
        }

        private string empName;
        public string EmpName
        {
            get
            {
                return empName;
            }
            set
            {
                empName = value;
            }
        }
    }
}

这是非常简单的代码,我只想将 Employee.cs 类中的 EmpIDEmpName 属性绑定到 MainWindow.xaml 中的 Textbox 的 Text属性上,但是当我运行代码时,这些文本框里什么也没有显示。请问我的绑定是否正确?

4个回答

154

这段代码将始终失败。

按照原文,它的意思是:“在我的DataContext属性上查找名为'Employee'的属性,并将其设置为DataContext属性”。显然这是不正确的。

如果要让您的代码像现在这样工作,请将窗口声明更改为:

<Window x:Class="SampleApplication.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SampleApplication"
    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
   <local:Employee/>
</Window.DataContext>

这将声明一个新的XAML命名空间(本地),并将DataContext设置为Employee类的实例。这将导致您的绑定显示默认数据(来自您的构造函数)。

然而,这很可能不是你真正想要的。相反,你应该有一个新的类(称之为MainViewModel),其中包含一个Employee属性,然后将其绑定到,如下所示:

public class MainViewModel
{
   public Employee MyEmployee { get; set; } //In reality this should utilize INotifyPropertyChanged!
}

现在你的 XAML 如下所示:

<Window x:Class="SampleApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:SampleApplication"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
       <local:MainViewModel/>
    </Window.DataContext>
    ...
    <TextBox Grid.Column="1" Grid.Row="0" Margin="3" Text="{Binding MyEmployee.EmpID}" />
    <TextBox Grid.Column="1" Grid.Row="1" Margin="3" Text="{Binding MyEmployee.EmpName}" />

现在您可以添加其他属性(其他类型、名称等)。有关更多信息,请参见实现模型-视图-视图模型模式


1
即使现在文本框没有填充。 - user1556433
1
@nkp,你有检查 System.Data 异常吗?它们应该会指导您找出任何打字错误。 - BradleyDotNET
1
我尚未成功地在XAML中绑定视图模型而不添加程序集。只是提醒一下。 xmlns:local="clr-namespace:SampleApplication;assembly=SampleApplication" - MistaGoustan
1
@MistaGoustan 是的,您 始终 需要使用 XMLNS 来引用您的视图模型类型。 - BradleyDotNET
1
我的项目在共享文件夹上,它一直出现类似的错误。 - MistaGoustan
2
需要注意的是,DataContext 仅在窗口类(代码后台)的构造函数中调用 InitializeComponent() 后设置。以防有人编写了依赖于数据上下文设置的初始化代码。 - Manuzor

27

首先,您应该在 Employee 类中创建包含员工详细信息的属性:

public class Employee
{
    public Employee()
    {
        EmployeeDetails = new EmployeeDetails();
        EmployeeDetails.EmpID = 123;
        EmployeeDetails.EmpName = "ABC";
    }

    public EmployeeDetails EmployeeDetails { get; set; }
}

如果你不这样做,你会在Employee构造函数中创建对象实例,并且失去对它的引用。

在XAML中,你应该创建Employee类的实例,然后将其赋值给DataContext

你的XAML应该像这样:

<Window x:Class="SampleApplication.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    xmlns:local="clr-namespace:SampleApplication"
   >
    <Window.Resources>
        <local:Employee x:Key="Employee" />
    </Window.Resources>
    <Grid DataContext="{StaticResource Employee}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="200" />
        </Grid.ColumnDefinitions>

        <Label Grid.Row="0" Grid.Column="0" Content="ID:"/>
        <Label Grid.Row="1" Grid.Column="0" Content="Name:"/>
        <TextBox Grid.Column="1" Grid.Row="0" Margin="3" Text="{Binding EmployeeDetails.EmpID}" />
        <TextBox Grid.Column="1" Grid.Row="1" Margin="3" Text="{Binding EmployeeDetails.EmpName}" />
    </Grid>
</Window>

现在,您已经创建了包含员工详细信息的属性,接下来您应该使用此属性进行绑定:

Text="{Binding EmployeeDetails.EmpID}"

9

这里有几个问题。

  1. 你不能将DataContext分配为DataContext="{Binding Employee}",因为它是复杂对象,无法作为字符串分配。所以你必须使用<Window.DataContext></Window.DataContext>语法。
  2. 你将表示数据上下文对象的类分配给视图,而不是单个属性,所以这里{Binding Employee}是无效的,你只需要指定一个对象。
  3. 现在当你使用以下有效的语法分配数据上下文时
   <Window.DataContext>
      <local:Employee/>
   </Window.DataContext>

要知道,你正在创建一个新的Employee类的实例,并将其分配为数据上下文对象。 可能在默认构造函数中没有任何内容,因此不会显示任何内容。但是,那么在代码后台文件中如何管理它呢?你需要对DataContext进行类型转换。

    private void my_button_Click(object sender, RoutedEventArgs e)
    {
        Employee e = (Employee) DataContext;
    }
  1. A second way is to assign the data context in the code behind file itself. The advantage then is your code behind file already knows it and can work with it.

    public partial class MainWindow : Window
    {
       Employee employee = new Employee();
    
       public MainWindow()
       {
           InitializeComponent();
    
           DataContext = employee;
       }
    }
    

我在代码后台设置"dataContext"时遇到的一个主要问题是,现在"ICommand"无法与其他事件一起使用,而且我正在使用一个窗口而不是viewModel。有什么解决方法吗? - RAMM-HDR
1
交换构造函数中的两行代码,即将“InitializeComponent();”放在最后,这样就可以解决你的问题。 - Samuel Vidal

0
可能可以行,只要你改一下就行了。
<Window x:Class="SampleApplication.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    DataContext="{Binding Employee}">

<Window x:Class="SampleApplication.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Employee">

(感谢上面的BradleyDotNET注意到了绑定源的问题。) 我知道这可能不是最好的答案,但我认为重要的是要添加(即当您想要将“子视图”添加到您的视图中,并且希望将其DataContext分配为“父视图”中的对象时。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接