属性更改时无法执行Checked事件

时间:2018-03-19 13:05:57

标签: c# wpf xaml

我有一个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

1 个答案:

答案 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);

更新2

如果您只想尽快执行操作,您确实可以将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>