【问题标题】:WPF Convert Called Once for ObservableCollection为 ObservableCollection 调用一次 WPF 转换
【发布时间】:2016-09-27 07:52:51
【问题描述】:

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

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

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

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

注意:为了简单起见,我将粘贴我的示例项目的整个代码您只需要在项目运行中创建这些文件

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();
    }
}

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

【问题讨论】:

  • 一个简单的解决方法是在ButtonBase_OnClick 末尾调用employee.RaisePropertyChanged("Employee")
  • @KooKiz 哇哇,你太棒了。我在这个问题上花了将近 1.5 天。请回答该评论,以便我稍后将其标记为答案。

标签: c# wpf xaml data-binding converter


【解决方案1】:

向集合中添加元素时,不会修改 Employee 属性,因此不会引发 NotifyPropertyChanged 事件。
一个简单的解决方法是在ButtonBase_OnClick 的末尾调用employee.RaisePropertyChanged("Employee")

【讨论】:

    【解决方案2】:

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

    解释是 Text 属性不需要集合,因此不侦听 CollectionChanged 事件。换句话说,ObservableCollection&lt;Person&gt; 正在通知更改,但没有人在收听通知。使用 KooKiz 方法显式告诉 TextBlock 好像“Emplyoee”属性已更改(而不仅仅是它背后的集合),TextBlock 正在侦听该属性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-01
      • 2014-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多