自我数据上下文绑定在 XAML 中不起作用,但在代码隐藏中工作



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

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 = 
@"Imagespic.bmp" },
new Model { Name = "Ada", LastName = "Lovelace", Age = 37, 
PicturePath = @"ImagesAdaLovelace.bmp" }};
// this.DataContext = this;
}
}

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

在 XAML 中分配DataContext时,在构造函数中调用InitilizeComponent()时,将分析所有 XAML。问题是:在分析 XAML 时,Models仍处于null状态,因为它在调用InitilizeComponent()后实例化。因此,所有绑定都会失败,因为在评估绑定时null绑定到的集合(在分析 xaml 时发生)。当您实例化Models时,视图不知道这一点,因为您尚未实现任何通知机制。

另一方面,在代码隐藏中分配 DataContext 时,会在分析完所有 XAML 后执行此操作,这会强制视图在分配时评估绑定...因此它有效。

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

  1. 更改初始化顺序

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

  1. 实现INotifyPropertyChanged接口。

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

从SO,很好,切中要害

更详细的解释在这里

来自 WPF Tutorial.net

  1. 使Models成为依赖属性。

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

请参阅此文章

你的问题是因为你有一个空的可观察集合。如果你移动你的代码,它将工作:

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 = 
@"Imagespic.bmp" },
new Model { Name = "Ada", LastName = "Lovelace", Age = 37, 
PicturePath = @"ImagesAdaLovelace.bmp" }};
InitializeComponent();
}
}

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

最新更新