WPF转换器和ObservableCollections

4
我正在将一个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");
}

当集合被绑定时,当有值时矩形是可见的,当集合为空时矩形不可见。但是,如果集合为空并且我在运行时添加一个值,则矩形不会出现(转换器的Convert方法甚至都没有触发)。我是否遗漏了什么,或者只是对IValueConverter要求过高了?

所以说……将ObservableCollection<T>.Count绑定到转换器可以使其按预期工作,因此我猜测将一个值添加到集合中不会触发PropertyChanged事件……我想暂时的解决方法可能是对该集合及其.Count方法进行多重绑定,但这听起来很糟糕…… - CatBusStop
3个回答

3

好的,这里是我使用 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#保持不变 :)

6
这个方法的原理是改变了"Count"属性并触发了转换器。在这种情况下,"Multi"转换器是无用的,你可以使用以下代码获得相同的效果:``其中,CountToVisibilityConverter 实现了 IValueConverter 接口,你只需将值(类型为 int)与 0 进行比较并返回 Visibility 即可。祝好! - daniell
1
继续daniell所说的,如果您使用ObservableCollection.SetItem,则此方法无法正常工作,因为它不会更新计数。 - hypehuman
1
可见性转换器是什么,@daniell!? - Matt Searles

2
我认为,如果Binding源已更新并通知了该更新(作为DependencyProperty或使用INotifyPropertyChanged),则Binding中的转换器始终会被调用。然而,如果添加或删除了一个项目,则ObservableCollection不会引发PropertyChanged事件,而是引发CollectionChanged事件。如果集合中的项目发生更改,则根本不会引发任何事件。即使项目本身引发了PropertyChanged,这也不会更新集合上的Binding,因为Binding源不是项目,而是集合。
我担心您的方法不会以这种方式起作用。您可以直接绑定到ObservableCollection.Count,并添加适当的数学转换器来执行反转和乘法,但是Count属性不执行更改通知,因此这不是选项。我认为您将不得不在ViewModel或代码后台中提供另一个属性来处理这些情况...
最好的问候,

3
好的,我会尽力进行翻译。以下是需要翻译的内容:Yes, I've already read the post you appear to have plagiarised this from (https://dev59.com/KU3Sa4cB1Zd3GeqPxrxv). The MultiValueConverter does the job in any case.是的,我已经阅读了你所抄袭的帖子(https://dev59.com/KU3Sa4cB1Zd3GeqPxrxv)。无论如何,MultiValueConverter都可以完成这项工作。 - CatBusStop
"抄袭" ?! 很高兴你找到了解决方案.. 最好的问候 - daniell

0

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

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


创建集合后设置DataContext只能让它在一开始生效,如果你在运行时添加值,它仍然不会改变。我有一个使用MultiValueConverters的解决方案,马上就会发布 :) - CatBusStop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接