WPF Convert 为 ObservableCollection 调用一次

WPF Convert Called Once for ObservableCollection

我的 wpf 应用程序中有 2 个网格,Grid Parent,Grid Child。当用户 select 父网格中的记录时,子网格显示该父网格记录的条目。在更改父项中的每个记录时,子项重新绑定与其对应的新值。将鼠标悬停在每一行上时,我设置了一个转换器,该转换器可以显示或隐藏在该记录的一列中的图标中。

问题: 当第一次绑定子网格时,鼠标悬停在记录上时它会调用该转换器。一旦我更改了父项中的记录,子网格就会重新绑定,但是当鼠标悬停在这些记录上时,不会调用转换器来显示隐藏图标。它会记住转换器返回的最后一个值。

要求的行为:要求的行为是转换器应在每一行鼠标悬停时调用。

我无法在此处粘贴实际代码,因此我制作了一个示例项目,如果我解决了该示例中的问题,它可能会解决我的问题。

注意:为了简单起见,我粘贴了示例项目的全部代码你只需要在项目[=中创建这些文件 67=].

BaseNotifyChanged.cs

public class BaseNotifyChanged : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged([CallerMemberName] string propertyname = "")
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyname));
        }
    }
}

型号:Person.cs

public class Person : BaseNotifyChanged
{
    private string _name;
    public string Name
    {
        get { return _name; }
        set 
        {
            if (this._name != value)
            {
                this._name = value;
                this.RaisePropertyChanged();
            }
        }
    }

    private string _email;
    public string Email
    {
        get { return _email; }
        set
        {
            if (this._email != value)
            {
                this._email = value;
                this.RaisePropertyChanged();
            }
        }
    }
}

查看模型:Employees.cs

public class Employees: BaseNotifyChanged
{
    public Employees()
    {
        this.Employee = new ObservableCollection<Person>()
        {
            new Person(){ Name = "Zeb", Email = "zeb@gmail.com"},
            new Person(){ Name = "Asad", Email = "asad@gmail.com"},
            new Person(){ Name = "Javeed", Email = "javeed@gmail.com"}
        };
    }
    private ObservableCollection<Person> _employee;

    public ObservableCollection<Person> Employee
    {
        get { return _employee; }
        set 
        {
            if (this._employee != value)
            {
                this._employee = value;
                this.RaisePropertyChanged();
            }
        }
    }

}

查看:MainWindow.xaml

<Grid>
    <Grid.Resources>
        <localCnr:ListToStringConverter x:Key="LtSCtr"></localCnr:ListToStringConverter>
    </Grid.Resources>
    <StackPanel>
        <TextBlock Text="{Binding Employee, Converter={StaticResource LtSCtr}}"/> 
        <Button Content="Add New Employee" Click="ButtonBase_OnClick"/>
    </StackPanel>
</Grid>

查看代码背后:MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public Employees employee { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        employee = new Employees();
        this.DataContext = employee;
    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        employee.Employee.Add(new Person(){ Name = "New Employee", Email = "new@gmail.com"});
    }
}

转换器:ListToStringConverter.cs

public class ListToStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ObservableCollection<Person> employess = value as ObservableCollection<Person>;
        StringBuilder sb = new StringBuilder();
        foreach (Person person in employess)
        {
            sb.Append(person.Name + " , ");
        }
        return sb.ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

据我所知,在我的原始场景中,网格正在重新绑定,但作为集合对象,它本身并没有更新,而是添加或删除了一个值,因此它没有调用转换。有什么建议吗? 提前致谢

向集合中添加元素时,您并未修改 Employee 属性,因此不会引发 NotifyPropertyChanged 事件。
一个简单的解决方法是在 ButtonBase_OnClick.

的末尾调用 employee.RaisePropertyChanged("Employee")

只是为了解释上面的答案,因为employee.Employee是一个ObservableCollection,你会期望它自动通知有界的TextBlock,但是当Employee列表更新时TextBlock仍然保持不变。

解释是文本 属性 不需要集合,因此不会侦听 CollectionChanged 事件。换句话说,ObservableCollection<Person> 正在通知更改,但没有人在收听通知。使用 KooKiz 方法明确告诉 TextBlock,就好像 "Emplyoee" 属性 已更改(而不仅仅是它后面的集合),TextBlock 正在侦听。