我有一个英雄课。它只有一个属性Name,它实现了有关更改的接口。
public class Hero : INotifyPropertyChanged, INotifyCollectionChanged
{
public string Name { get { return _name; }
set
{
_name = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
if (CollectionChanged != null)
{
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace));
}
}
}
private string _name = "";
}
我的xaml如下。我将文本的datacontext绑定到名为Heros的集合中,该集合在后面的代码中定义。
<Window x:Class="Chap21_2.TestCollection"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestCollection" Height="640" Width="480"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBox Grid.Row="1" Text="{Binding Name}" DataContext="{Binding Heros}"></TextBox>
<Button Grid.Row="2" Content="aa" ></Button>
</Grid>
</Window>
这里是我的后代码。它初始化集合,问题是当Init()顺序改变时,结果是不同的。
public partial class TestCollection : Window
{
public ObservableCollection<Hero> Heros { get { return _heros; } set { _heros = value; } }
private ObservableCollection<Hero> _heros = new ObservableCollection<Hero>();
public TestCollection()
{
// If move Init() here, it'll works.
InitializeComponent();
Init();
}
void Init()
{
Hero hero = new Hero("Bu Lv", 100, 88, 100, 30);
_heros.Add(hero);
hero.HP = 88;
hero = new Hero("Fei Zhang", 100, 88, 100, 30);
hero.HP = 90;
_heros.Add(hero);
}
}
当我启动代码时,文本框不显示&#34; Bu Lv&#34;我期望。 但是如果我在InitializedComponent()之前移动Init(),它就可以工作。 为什么呢?
答案 0 :(得分:0)
这可能是由于将集合绑定到单个文本框。如果我将其更改为使用ItemsControl,则Init可以在InitializeComponent之后。这是我做的事情。
public class Hero : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _name = string.Empty;
public string Name
{
get { return _name; }
set
{
_name = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
这包括您的原件以及用于说明目的的一些更改。
<Window x:Class="Chap21_2.TestCollection"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestCollection" Height="640" Width="480"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<!-- Your original binding -->
<TextBox Grid.Row="0" Text="{Binding Name}" DataContext="{Binding Heros}" />
<!-- My added ItemsControl for example purposes -->
<ItemsControl Grid.Row="1" ItemsSource="{Binding Heros}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Name}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Grid.Row="2" Content="aa" ></Button>
</Grid>
</Window>
您的示例并未包含所有其他属性,因此我为此示例的目的对其进行了评论。
public partial class TestCollection : Window
{
public ObservableCollection<Hero> Heros { get { return _heros; } set { _heros = value; } }
private ObservableCollection<Hero> _heros = new ObservableCollection<Hero>();
public TestCollection()
{
// Putting this here allows the collection to populate BEFORE the UI is initialized.
// Init();
InitializeComponent();
// Putting it here is normal. The ItemsControl works, but the single TextBox binding will not.
Init();
}
private void Init()
{
Hero hero;
//Hero hero = new Hero("Bu Lv", 100, 88, 100, 30);
//hero.HP = 88;
hero = new Hero();
hero.Name = "Bu Lv";
_heros.Add(hero);
//hero = new Hero("Fei Zhang", 100, 88, 100, 30);
//hero.HP = 90;
hero = new Hero();
hero.Name = "Fei Zhang";
_heros.Add(hero);
}
}
我的建议是,如果您想要从集合中显示单个模型,您可能需要添加一个&#34; SelectedHero&#34;或仅包含单个Hero实例的类似属性。绑定到某个东西的集合通常用于渲染集合中的所有实例。
无论你怎样看待它,你都可以在IntializeComponent()之前或之后放置Init(),因为你没有直接与UI交互。