【问题标题】:Self DataContext binding not working in XAML but working in code behind自我 DataContext 绑定在 XAML 中不起作用,但在后面的代码中起作用
【发布时间】:2018-09-24 17:40:36
【问题描述】:

当我尝试通过 DataContext="{Binding RelativeSource={RelativeSource Self}}" 绑定 Window 的 Datacontext 时,它不起作用,如果我在代码隐藏中做同样的事情,它工作得很好。 我假设错了吗 this.DataContext=this 在代码隐藏窗口的构造函数中。

XAML 的完整代码是...

  <Window x:Class="SampleDemoListBox.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:SampleDemoListBox"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    >
    <Window.Resources>
     <DataTemplate x:Key="ModelItemTemplate" >
      <StackPanel Margin="25" Orientation="Horizontal">
      <Image VerticalAlignment="Top" x:Name="ModelPicture" Width="150" 
        Source="{Binding PicturePath}"></Image>
        <Grid VerticalAlignment="Top">
           <Grid.RowDefinitions>
                 <RowDefinition></RowDefinition>
                  <RowDefinition></RowDefinition>
                  <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                   <ColumnDefinition></ColumnDefinition>
                   <ColumnDefinition></ColumnDefinition>
             </Grid.ColumnDefinitions>
                    <Label VerticalAlignment="Center" FontWeight="Bold" Content="Name:" Grid.Row="0" Grid.Column="0"></Label>
                    <Label VerticalAlignment="Center" FontWeight="Bold" Grid.Row="1" Grid.Column="0" Content="LastName:"></Label>
                    <Label VerticalAlignment="Center" FontWeight="Bold" Grid.Row="2" Grid.Column="0" Content="Age:"></Label>
                    <TextBlock  VerticalAlignment="Center" Grid.Row="0" Grid.Column="1" x:Name="Name" Width="120" Text="{Binding Name}" ></TextBlock>
                    <TextBlock  VerticalAlignment="Center" Grid.Row="1" Grid.Column="1" x:Name="LastName" Width="120" Text="{Binding LastName}" ></TextBlock>
                    <TextBox  VerticalAlignment="Center" Grid.Row="2" Grid.Column="1" x:Name="Age" Width="120" Text="{Binding Age}" ></TextBox>

                </Grid>
            </StackPanel>
        </DataTemplate>

      </Window.Resources>
      <Grid>
      <StackPanel>
        <ListBox x:Name="LstModels" Margin="25" ItemsSource="{Binding 
          Models}" ItemTemplate="{Binding Source={StaticResource 
           ModelItemTemplate}}"></ListBox>
           <Button Width="120" Height="40" Click="AddModel_OnClick" 
           Content="Add Model" ></Button>
       </StackPanel>
       </Grid>
       </Window>

而代码隐藏是...

    public partial class MainWindow : Window
     {
        public ObservableCollection<Model> Models{ get; set; }
          public MainWindow()
          {
              InitializeComponent();
              Models= new ObservableCollection<Model> { new Model{ Name = 
             "Shabana", LastName = "Parveen", Age = 35, PicturePath = 
               @"Images\pic.bmp" },
             new Model { Name = "Ada", LastName = "Lovelace", Age = 37, 
             PicturePath = @"Images\AdaLovelace.bmp" }};

           // this.DataContext = this;

          }
     }

【问题讨论】:

    标签: wpf binding datacontext


    【解决方案1】:

    您的问题是因为您有一个 null observablecollection。如果您移动代码,它将起作用:

    public partial class MainWindow : Window
     {
        public ObservableCollection<Model> Models{ get; set; }
          public MainWindow()
          {
    
              Models= new ObservableCollection<Model> { new Model{ Name = 
             "Shabana", LastName = "Parveen", Age = 35, PicturePath = 
               @"Images\pic.bmp" },
             new Model { Name = "Ada", LastName = "Lovelace", Age = 37, 
             PicturePath = @"Images\AdaLovelace.bmp" }};
    
              InitializeComponent();
    
          }
     }
    

    您应该考虑使用单独的类作为视图模型和 MVVM。

    【讨论】:

      【解决方案2】:

      您观察到的行为是由于您初始化视图和实例化ObservableCollection 的顺序。

      当您在 XAML 中分配 DataContext 时,当您在构造函数中调用 InitilizeComponent() 时,您的所有 XAML 都会被解析。问题是:在解析您的 XAML 时,Models 仍然是 null,因为它在您调用 InitilizeComponent() 之后被实例化。出于这个原因,所有绑定都会失败,因为您绑定到的集合是null,当评估绑定时(在解析 xaml 时会发生这种情况)。当您实例化Models 时,视图不会意识到这一点,因为您还没有实现任何通知机制。

      另一方面,当您在后面的代码中分配 DataContext 时,您会在解析所有 XAML 之后执行此操作,这会强制 View 在分配时评估绑定...因此它可以工作。

      我能想到的至少有 3 个解决方案:

      1. 更改初始化顺序

      正如 Andy 在他的回答中建议的那样,如果您首先实例化 Models 集合,然后调用 InitilizeComponent(),它将起作用。在解析 XAML 时,视图将具有非空 DataContext,因此所有数据都将通过绑定传播到您的视图。

      1. 实现INotifyPropertyChanged接口。

      这将允许您在方便时实例化Models,然后引发PropertyChanged 事件以通知视图。这也可以。但是如果你遇到这么多麻烦,你真的应该考虑使用 MVVM 模式(网上有很多教程)。我将把实现的细节留给你,因为那里有无数的例子和教程。您可以从以下几个方面入手:

      From SO, nice and to the point

      More elaborate explanation here

      From WPF Tutorial.net

      1. Models 设为依赖属性。

      如果您坚持在后面的代码(而不是 MVVM)中执行此操作,DependencyPropeties 将运行良好。依赖属性有自己的通知机制。尽管非常冗长,但它们很容易实现。下面是一个很好的来源,但你可以通过谷歌搜索找到很多。

      See this article

      【讨论】:

      • 谢谢 Nik,您的解释很有帮助。干杯
      • 尼克,您的回答确实有助于我理解引擎盖下发生的事情。我计划稍后实现 MVVM。现在试图逐步理解这些概念。干杯
      猜你喜欢
      • 1970-01-01
      • 2019-03-07
      • 1970-01-01
      • 1970-01-01
      • 2016-04-10
      • 2019-01-05
      • 1970-01-01
      • 1970-01-01
      • 2014-06-13
      相关资源
      最近更新 更多