【问题标题】:WPF Converters and ObservableCollectionsWPF 转换器和 ObservableCollections
【发布时间】:2011-09-23 12:45:21
【问题描述】:

我将 ObservableCollection 绑定到一个控件,该控件具有一个转换器,可以根据集合是否有任何值来更改其可见性:

简化示例:

XAML:

<Window.Resources>
    <local:MyConverter x:Key="converter"/>
</Window.Resources>

<Grid x:Name="grid">
    <Rectangle Height="100" Width="200" Fill="CornflowerBlue"
                Visibility="{Binding Converter={StaticResource converter}}"/>
    <Button Content="click" 
            HorizontalAlignment="Left" VerticalAlignment="Top" 
            Click="Button_Click"/>
</Grid>

C#:

ObservableCollection<string> strings;

public MainWindow()
{
    InitializeComponent();

    strings = new ObservableCollection<string>();
    grid.DataContext = strings;
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    strings.Add("new value");
}

当集合被绑定时,Rectangle 在有值时可见,而在集合为空时不可见。但是,如果集合为空并且我在运行时添加了一个值,则 Rectangle 不会出现(甚至不会触发转换器的 Convert 方法)。我是遗漏了什么还是只是想对 IValueConverter 提出太多要求?

【问题讨论】:

  • 所以...绑定到 ObservableCollection.Count 使转换器按预期工作,所以我猜测向集合添加值不会触发 PropertyChanged 事件...临时我想的解决方案是多绑定集合和它的 .Count 方法,但这听起来很讨厌......

标签: wpf observablecollection converter


【解决方案1】:

好的,这就是我使用MultiValueConverter 解决问题的方法

转换器现在看起来像:

public object Convert(
    object[] values, 
    Type targetType, 
    object parameter, 
    System.Globalization.CultureInfo culture)
{
    ObservableCollection<string> strings = 
        values[0] as ObservableCollection<string>;

    if (strings == null || !strings.Any())
        return Visibility.Collapsed;
    else
        return Visibility.Visible;
}

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

XAML 现在看起来像:

<Rectangle Height="100" Width="200" Fill="CornflowerBlue">
    <Rectangle.Visibility>
        <MultiBinding Converter="{StaticResource converter}">
            <Binding Path="."/>
            <Binding Path="Count"/>
        </MultiBinding>
    </Rectangle.Visibility>
</Rectangle>

C# 保持不变 :)

【讨论】:

  • 这个工作的原因是“计数”属性发生了变化,它触发了转换器。在这种情况下,“Multi”转换器是无用的,与使用 &lt;Rectangle Height="100" Width="200" Fill="CornflowerBlue" Visibility={Binding Path=Count, Mode=OneWay, Converter={StaticResource CuntToVisibilityConverter}" /&gt; 获得的相同,其中 CountTovisibilityConverter 实现 IValueConverter,您只需将值(int 类型)与 0 进行比较即可返回可见性。再次,最好的问候
  • 跟进 daniell 所说的,如果您使用 ObservableCollection.SetItem,这将不起作用,它不会更新计数。
  • 可见性转换器@daniell!?
【解决方案2】:

我认为,如果 Binding 源已更新并通知该更新(作为 DependencyProperty 或使用 INotifyPropertyChanged),则始终调用 Binding 中的转换器。但是,如果已添加或删除项目,则 ObservableCollection 不会引发 PropertyChanged 事件,但会引发 CollectionChanged 事件。如果集合中的项目发生更改,它根本不会引发任何事件。即使项目本身引发 PropertyChanged,这也不会更新集合上的 Binding,因为 Binding 源不是项目,而是集合。

我担心你的方法不会这样。您可以直接绑定到 ObservableCollection.Count 并向其添加适当的数学转换器以执行求逆和乘法,但 Count 属性不执行更改通知,因此没有选项。我认为您将不得不在处理这些情况的 ViewModel 或代码隐藏中提供另一个属性...

最好的问候,

【讨论】:

  • 是的,我已经阅读了您似乎抄袭了 (stackoverflow.com/questions/2816163/…) 的帖子。 MultiValueConverter 在任何情况下都能完成这项工作
  • “抄袭”?!很高兴你找到你的解决方案.. 最好的问候
【解决方案3】:

创建集合后必须设置DataContext;很可能您将“strings”集合初始化为“null”,将构造函数中的 DataContext 设置为该值(例如 null),然后实际创建集合——这样,DataContext 保持为 null。

您必须在创建集合后再次设置 DataContext。

【讨论】:

  • 在创建集合后设置 DataContext 只意味着它工作一次,如果在运行时添加值,它仍然不会改变。我有一个使用 MultiValueConverters 的解决方案,我会在一分钟内发布:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-24
相关资源
最近更新 更多