wpf中什么时候会调用ValueConverter的Convert方法
我有一个绑定到列表框的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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
可以使用多重绑定转换器来克服这个问题。然后,您可以同时绑定到
Collection.Count
属性和集合。计数将触发绑定重新评估,然后您使用第二个绑定根据需要实际转换值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我认为,如果
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 theBinding
source has been updated and notifies about that update (as aDependencyProperty
or usingINotifyPropertyChanged
). However, anObservableCollection
does not raise thePropertyChanged
event if an item has been added or removed, but it raises theCollectionChanged
event. It does not raise any event at all if an item in the collection is changed. Even if the item itself raisesPropertyChanged
, this will not update theBinding
on the collection since theBinding
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 theCount
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...当绑定发生或属性更改时,将调用转换器。因此,每当布尔值发生变化时,都会调用转换器来获取布尔值。您的集合设置一次,即在发生绑定并使用转换器时。当集合的内部发生变化(集合被添加或删除)时,属性不会改变(即您没有绑定新的集合),因此您的转换器不会再次触发。
使用视图模型并包装您的集合并添加另一个属性,例如实现更改通知的计数。您可以使用此处中的包装类,它将包装您的集合,并且可以轻松地在其中添加属性。
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.