【问题标题】:WPF ListBox property binding not updatingWPF ListBox 属性绑定未更新
【发布时间】:2014-04-28 03:07:04
【问题描述】:

我有以下设置:

XAML:

<ListBox x:Name="MyList" ItemsSource="{Binding MyItems}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Image Height="20" Width="20" Visibility="{Binding HasInformation, Converter={StaticResource VC}, ConverterParameter=True}" Source="/path/to/information.png" />
                <TextBlock Text="{Binding Name}" VerticalAlignment="Center" Padding="5,0" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

注意:传入的 ConverterParameter 只是控制可见性是“折叠”(False)还是“隐藏”(True),所以在这种情况下,我希望可见性为 @ 987654324@.

ViewModel 代码段:

private ObservableCollection<IItem> _MyItems;
public ObservableCollection<IItem> MyItems
{
    get
    {
        return _MyItems;
    }
    set
    {
        NotifyPropertyChanged(ref _MyItems, value, "MyItems");
    }
}

private IItem _SelectedItem;
public IItem SelectedItem
{
    get
    {
        return _SelectedItem;
    }
    set
    {
        NotifyPropertyChanged(ref _SelectedItem, value, "SelectedItem");
    }
}

物品:

public interface IItem
{
    string Name { get; }
    bool HasInformation { get; set; }
}

我将数据库中的IItem 列表的实现填充到列表中,如果HasInformation 为真,则信息图标会适当显示。这一切正常。

但是,如果我手动设置HasInformation,则视图不会更新。我试过了:

在 ViewModel 中:

OnPropertyChanged("MyItems");
MyItems[MyItems.IndexOf(SelectedItem)].HasInformation = true;
// Note that "SelectedItem" is persisted correctly, and always
// points to the selected item that we want to update.

在后面的代码中:

MyList.GetBindingExpression(ItemsControl.ItemsSourceProperty).UpdateTarget();

所有这些都会触发MyItems 属性的getter,但视图永远不会更新,图标也永远不会显示。我已确保我更新的项目的HasInformation 属性确实如此,其实还是true。我已附加到PropertyChanged 事件,以确保它触发"MyItems" 的属性更改(这也会触发getter),我什至确保它使用正确的值调用值转换器HasInformation 属性(它是!),那么我错过了什么?我没有正确处理图像显示/隐藏或可见性值转换是否有什么奇怪的地方?

【问题讨论】:

  • 显示您实施 HasInformation 的位置
  • 类似于@Blam,我怀疑IItem接口中的HasInformation实现没有实现INotifyPropertyChanged。仅仅因为您使用 ObservableCollection 并不意味着当包含项目中的属性发生更改时,ListBox 或其他元素将得到通知。仅当集合更改(添加/删除项目)时,才会通知列表框。
  • +1。如果您的 IItem 实现是由您的数据库提供的,那么您必须使用您的数据库代码提供的任何机制来允许您将属性通知注入它创建的对象(我个人使用 Castle Dynamic Proxy 来使用 NHibernate 执行此操作)。另一种方法是为视图模型中的每个数据模型创建一个包装器,然后自己添加该功能。
  • 为什么我被否决了?这是一个合理的问题。 ://
  • 您被要求两次展示 HasInformation 的实现,但没有。这就是问题所在。

标签: c# wpf mvvm binding listbox


【解决方案1】:

ObservableCollection 只通知集合的变化,而不是每个项目的变化。为了实现您的目标,选项之一是将 IItem 从接口更改为实现 INotifyPropertyChanged 接口的类(或在 IItem 具体类型中实现它),并将其与 ViewModel 的 PropertyChanged 委托挂钩(记得取消订阅它)。请参阅下面的一些代码。

视图模型

public class MyViewModel: INotifyPropertyChanged
{
    private ObservableCollection<Item> _MyItems;
    public ObservableCollection<Item> MyItems
    {
        get
        {
            return _MyItems;
        }
        set
        {
            if (_MyItems != null)
            {
                foreach (var item in _MyItems)
                {
                    item.PropertyChanged -= PropertyChanged;
                }
            }

            if (value != null)
            {
                foreach (var item in value)
                {
                    item.PropertyChanged += PropertyChanged;
                }
            }

            OnPropertyChanged();
        }
    }

    private Item _SelectedItem;
    public Item SelectedItem
    {
        get
        {
            return _SelectedItem;
        }
        set
        {
            _SelectedItem = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

物品

public class Item : INotifyPropertyChanged
{
    private string _name;
    private bool _hasInformation;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }

    public bool HasInformation
    {
        get { return _hasInformation; }
        set
        {
            _hasInformation = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

【讨论】:

  • 我不明白为什么强制绑定更新或调用 OnPropertyChanged("MyItems"); 不起作用。这不应该强制列表更新吗?
  • 无论如何,这就是问题所在。我实际上在 Castle 组件/提供程序中实现了这个接口,我害怕实现 INotifyPropertyChanged,因为我不确定这是否会破坏 MVVM 模式。在我在接口契约和实际实现上都实现了它之后,它工作得很好。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-18
  • 1970-01-01
  • 2017-03-30
  • 1970-01-01
  • 1970-01-01
  • 2016-08-20
  • 1970-01-01
相关资源
最近更新 更多