C# 当datacontext是列表时,为什么我的文本框没有正确初始化?
我有一个英雄班。它只有一个属性名,并且实现了关于更改的接口C# 当datacontext是列表时,为什么我的文本框没有正确初始化?,c#,wpf,C#,Wpf,我有一个英雄班。它只有一个属性名,并且实现了关于更改的接口 public class Hero : INotifyPropertyChanged, INotifyCollectionChanged { public string Name { get { return _name; } set { _name = value; if (PropertyChanged != null)
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);
}
}
公共部分类TestCollection:窗口
{
公共ObservableCollection Heros{get{return{U Heros;}set{U Heros=value;}}
私有ObservableCollection_heros=新ObservableCollection();
公共测试集合()
{
//如果将Init()移到这里,它就会工作。
初始化组件();
Init();
}
void Init()
{
英雄=新英雄(“步吕”,100,88,100,30);
_添加(英雄);
hero.HP=88;
英雄=新英雄(“张飞”,100,88,100,30);
hero.HP=90;
_添加(英雄);
}
}
当我启动代码时,文本框并没有显示我期望的“bulv”。
但是如果我在InitializedComponent()之前移动Init(),它就会工作。
为什么?这可能是由于将集合绑定到单个文本框。如果我将其更改为使用ItemsControl,则Init可以位于InitializeComponent之后。以下是我所做的事情 Hero.cs TestCollection.xaml 这包括您的原稿,并作了一些更改,以便于说明
<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>
TestCollection.xaml.cs
您的示例没有包括所有其他属性,因此出于本示例的目的,我将它们注释掉
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);
}
}
公共部分类TestCollection:窗口
{
公共ObservableCollection Heros{get{return{U Heros;}set{U Heros=value;}}
私有ObservableCollection_heros=新ObservableCollection();
公共测试集合()
{
//将其放在此处允许在初始化UI之前填充集合。
//Init();
初始化组件();
//把它放在这里是正常的。ItemsControl可以工作,但是单个文本框绑定不能。
Init();
}
私有void Init()
{
英雄;
//英雄=新英雄(“步吕”,100,88,100,30);
//hero.HP=88;
英雄=新英雄();
hero.Name=“Bu-Lv”;
_添加(英雄);
//英雄=新英雄(“张飞”,100,88,100,30);
//hero.HP=90;
英雄=新英雄();
hero.Name=“张飞”;
_添加(英雄);
}
}
我的建议是,如果要显示集合中的单个模型,可以添加“SelectedHero”或仅包含单个Hero实例的类似属性。绑定到某个对象的集合通常用于呈现集合中的所有实例
无论从哪种角度看,您都可以将Init()放在initializeComponent()之前或之后,因为您没有直接与UI交互。对于初学者来说,您不需要在只有string属性的类上实现collection changed。我也不清楚为什么要在xaml中将datacontext设置为自绑定,简单地设置datacontext=this会更容易;在初始化组件后的代码隐藏中,如果这是您想要的,请Hanks Chris。绑定到组合框怎么样?我发现如果我将Init()放在InitializeComponent()之前,组合框将自动选择第一条记录。但是如果我将Init()放在InitializeComponent()之后,它将不会选择任何记录。xaml代码如下所示:。有什么建议吗?@System我不知道为什么它没有通知我你的评论,但我在浏览我的列表时看到了。当
Init()
在InitializeComponent()
之后时,它不选择任何内容的原因是该控件是使用空集合初始化的。在我的表单中,有一个主视图模型,它具有表单的所有从属属性。这包括各种可观察到的集合。SelectedIndex
将绑定到其中一个属性。然后,这只是在填充之后初始化索引的问题。由于没有这样的绑定,您需要直接访问它。如果将Init()
放在后面,则可以通过编程方式选择它。在组合框中添加一个名称,如
,然后您可以这样选择它:cboHeroes.SelectedIndex=0代码>。或者,为窗体创建一个主视图模型,并使用DependencyProperties单向或双向绑定。请记住我关于“不直接与UI交互”的说明。如果要在SelectedIndex
更改后执行代码,则必须在InitializeComponent()之后执行。它还假设集合中有内容。谢谢你,克里斯。我得到了它。
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);
}
}