wpf中什么时候会调用ValueConverter的Convert方法

发布于 2024-09-01 04:31:35 字数 3323 浏览 2 评论 0原文

我有一个绑定到列表框ObservableCollection和绑定到按钮布尔属性。然后,我定义了两个转换器,一个对集合进行操作,另一个对布尔属性进行操作。每当我修改布尔属性时,都会调用转换器的 Convert 方法,而如果我修改可观察集合,则不会调用该方法。我缺少什么?

供您参考的片段、

xaml 片段、

<Window.Resources>
    <local:WrapPanelWidthConverter x:Key="WrapPanelWidthConverter" />
    <local:StateToColorConverter x:Key="StateToColorConverter" />
</Window.Resources>
<StackPanel>
    <ListBox x:Name="NamesListBox" ItemsSource="{Binding Path=Names}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel x:Name="ItemWrapPanel" Width="500" Background="Gray">
                    <WrapPanel.RenderTransform>
                        <TranslateTransform x:Name="WrapPanelTranslatation" X="0" />
                    </WrapPanel.RenderTransform>
                    <WrapPanel.Triggers>
                        <EventTrigger RoutedEvent="WrapPanel.Loaded">
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="WrapPanelTranslatation" Storyboard.TargetProperty="X" To="{Binding Path=Names,Converter={StaticResource WrapPanelWidthConverter}}" From="525"  Duration="0:0:2" RepeatBehavior="100" />
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                    </WrapPanel.Triggers>
                </WrapPanel>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Label Content="{Binding}" Width="50" Background="LightGray" />
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <Button Content="{Binding Path=State}" Background="{Binding Path=State, Converter={StaticResource StateToColorConverter}}" Width="100" Height="100" Click="Button_Click" />
</StackPanel>   

代码片段背后的代码

public class WrapPanelWidthConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ObservableCollection<string> aNames = value as ObservableCollection<string>;
        return -(aNames.Count * 50);
    }

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


public class StateToColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        bool aState = (bool)value;
        if (aState)
            return Brushes.Green;
        else
            return Brushes.Red;
    }

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

I have an ObservableCollection bound to a list box and a boolean property bound to a button. I then defined two converters, one that operates on the collection and the other operates on the boolean property. Whenever I modify the boolean property, the converter's Convert method is called, where as the same is not called if I modify the observable collection. What am I missing??

Snippets for your reference,

xaml snipet,

<Window.Resources>
    <local:WrapPanelWidthConverter x:Key="WrapPanelWidthConverter" />
    <local:StateToColorConverter x:Key="StateToColorConverter" />
</Window.Resources>
<StackPanel>
    <ListBox x:Name="NamesListBox" ItemsSource="{Binding Path=Names}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel x:Name="ItemWrapPanel" Width="500" Background="Gray">
                    <WrapPanel.RenderTransform>
                        <TranslateTransform x:Name="WrapPanelTranslatation" X="0" />
                    </WrapPanel.RenderTransform>
                    <WrapPanel.Triggers>
                        <EventTrigger RoutedEvent="WrapPanel.Loaded">
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="WrapPanelTranslatation" Storyboard.TargetProperty="X" To="{Binding Path=Names,Converter={StaticResource WrapPanelWidthConverter}}" From="525"  Duration="0:0:2" RepeatBehavior="100" />
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                    </WrapPanel.Triggers>
                </WrapPanel>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Label Content="{Binding}" Width="50" Background="LightGray" />
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <Button Content="{Binding Path=State}" Background="{Binding Path=State, Converter={StaticResource StateToColorConverter}}" Width="100" Height="100" Click="Button_Click" />
</StackPanel>   

code behind snippet

public class WrapPanelWidthConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ObservableCollection<string> aNames = value as ObservableCollection<string>;
        return -(aNames.Count * 50);
    }

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


public class StateToColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        bool aState = (bool)value;
        if (aState)
            return Brushes.Green;
        else
            return Brushes.Red;
    }

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

兮颜 2024-09-08 04:31:35

可以使用多重绑定转换器来克服这个问题。然后,您可以同时绑定到 Collection.Count 属性和集合。计数将触发绑定重新评估,然后您使用第二个绑定根据需要实际转换值

<TextBlock IsHitTestVisible="false"
    Margin="5,0"
    TextTrimming="CharacterEllipsis"
    VerticalAlignment="Center"
    DockPanel.Dock="Left" >
    <TextBlock.Text>
        <MultiBinding Converter="{Resources:ListToStringConverter}">
            <Binding Path="List.Count" />
            <Binding Path="List" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

A multibinding converter can be used to overcome this issue. You can then bind to the Collection.Count property and the collection at the same time. The count will trigger the binding to get re-evaluated and then you use the second binding to actually transform the values as required

<TextBlock IsHitTestVisible="false"
    Margin="5,0"
    TextTrimming="CharacterEllipsis"
    VerticalAlignment="Center"
    DockPanel.Dock="Left" >
    <TextBlock.Text>
        <MultiBinding Converter="{Resources:ListToStringConverter}">
            <Binding Path="List.Count" />
            <Binding Path="List" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>
何其悲哀 2024-09-08 04:31:35

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

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

I think the converter in a Binding is always called if the Binding source has been updated and notifies about that update (as a DependencyProperty or using INotifyPropertyChanged). However, an ObservableCollection does not raise the PropertyChanged event if an item has been added or removed, but it raises the CollectionChanged event. It does not raise any event at all if an item in the collection is changed. Even if the item itself raises PropertyChanged, this will not update the Binding on the collection since the Binding source is not the item, but the collection.

I fear your approach will not work this way. You could bind directly to ObservableCollection.Count and add an appropriate math converter to it to perform the inversion and multiplication, but the Count property does not perform change notification, so this no option. I think you will have to provide another property in your ViewModel or code-behind which handles these cases...

横笛休吹塞上声 2024-09-08 04:31:35

当绑定发生或属性更改时,将调用转换器。因此,每当布尔值发生变化时,都会调用转换器来获取布尔值。您的集合设置一次,即在发生绑定并使用转换器时。当集合的内部发生变化(集合被添加或删除)时,属性不会改变(即您没有绑定新的集合),因此您的转换器不会再次触发。

使用视图模型并包装您的集合并添加另一个属性,例如实现更改通知的计数。您可以使用此处中的包装类,它将包装您的集合,并且可以轻松地在其中添加属性。

A converter is called when the binding happens or the property changes. So your converter is called for your boolean whenever the value of the boolean changes. Your collection is set once and that is when the binding occurs and the converter is used. When the internals of the collection change (the collection is added to or removed from) the property does not change (i.e. you are not binding a new collection) so your converter does not fire again.

Use a view model and wrap your collection and add another property such as count that implements change notification. You can use this wrapper class from here which will wrap your collection and it will be easy to add a property there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文