我有一个Combobox绑定了以这种方式定义的Contact
列表:
public List<Contact> Contacts { get;set; } = new List<Contact>();
public class Contact
{
public bool IsFavourite { get; set; }
public bool IsChecked { get; set; }
public string Name { get; set; }
}
注意:Contact
类工具INotifyPropertyChange
,我在示例中没有写过。
Contacts
列表以ComboBox
的方式限制在以下方式:
<ComboBox ItemsSource="{Binding Contacts}"
ItemTemplate="{StaticResource CombinedTemplate}" />
其中CombinedTemplate
包含以下内容:
<DataTemplate x:Key="NormalItemTemplate">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Name}" Checked="Contact_Checked" Unchecked="Contact_Unchecked" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="CombinedTemplate">
<ContentPresenter x:Name="Presenter" Content="{Binding}"
ContentTemplate="{StaticResource NormalItemTemplate}" />
</DataTemplate>
正如您所看到的,我将IsChecked
CheckBox
绑定到代码后面的IsChecked
属性,因此假设在Contacts
列表中添加了此项:
var contact = new Contact();
contact.IsChecked = true;
contact.IsFavourite = true;
contact.Name = "Foo";
Contacts.Add(contact);
Checked
的{{1}}应该会自动触发,因为CheckBox
是真的,但我没有做到这一点。
我做错了什么?感谢。
更新
正如答案中所建议的那样修复此问题&#34; bug&#34;我应该处理IsChecked
事件,所以我做了:
Loaded
在我做的事件中:
<ComboBox ItemsSource="{Binding Contacts}"
Loaded="ContactMenuComboBox_Loaded"
ItemTemplate="{StaticResource CombinedTemplate}" />
private void ContactMenuComboBox_Loaded(object sender, RoutedEventArgs e)
{
foreach (var contact in Contacts)
{
if (contact.IsFavourite)
{
contact.IsChecked = true;
}
}
}
属性设置正确,遗憾的是IsChecked
事件未触发。
忘了说,如果我将IsChecked
的代码放在一个按钮中,然后按下它,那么事件ContactMenuComboBox_Loaded
就会被触发。
这是一个非常奇怪的情况。
更新#2
这是IsChecked
事件的内容:
Checked
答案 0 :(得分:1)
我已经与WPF核对过,你确实是对的! 第一次绑定评估不会触发 Checked
事件,只会执行后续调用。这与事件被解雇的UWP形成鲜明对比。
作为一种变通方法,如果您需要在首次绑定值后立即执行操作,则可以处理Loaded
事件。但是,如果您将应用程序实现为MVVM,那么最好在Checked
属性的setter中推送IsChecked
逻辑。
<CheckBox IsChecked="{Binding IsChecked}"
Content="{Binding Name}"
Loaded="Contact_Loaded"
Checked="Contact_Checked" Unchecked="Contact_Unchecked" />
在Loaded
方法中执行以下操作:
var checkbox = (CheckBox)sender;
if ( checkbox.IsChecked ) Contact_Checked(this, e);
if ( !checkbox.IsChecked ) Contact_UnChecked(this, e);
如果您只想尽快执行操作,您确实可以将Loaded
事件附加到您的窗口并执行以下操作:
foreach (var contact in Contacts)
{
if (contact.IsFavourite)
{
Task.Factory.StartNew(() =>
{
ContactController.GetLeagues(contact);
})
.ContinueWith((prevTask) =>
{
CheckTaskException(prevTask);
});
}
}
当然,为避免代码重复,您可以将此代码提取到带有Contact
参数的单独方法中。
问题是您的Contacts
属性是正常的List
。在这种情况下,数据绑定控件在首次绑定后不会更新该列表的任何更改。您应该使用ObservableCollection<T>
代替:
public ObservableCollection<Contact> Contacts { get; set; } =
new ObservableCollection<Contact>();
此外,当其中一个模板仅包含另一个ContentPresenter
时,我看不出有两个数据模板。您可以将其简化为NormalItemTemplate
:
<ComboBox ItemsSource="{Binding Contacts}"
ItemTemplate="{StaticResource NormalItemTemplate}" />
最后,Name
的数据绑定不正确,Item.
前缀不应该在那里:
<DataTemplate x:Key="NormalItemTemplate">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}"
Content="{Binding Name}"
Checked="Contact_Checked" Unchecked="Contact_Unchecked" />
</StackPanel>
</DataTemplate>