Quando o método convertido do valueConverter será chamado no WPF
-
26-09-2019 - |
Pergunta
eu tenho um ObservableCollection ligado a a caixa de listagem e a boleano propriedade ligada a um botão. Eu então defini dois conversores, um que opera na coleção e o outro opera na propriedade booleana. Sempre que modifico a propriedade booleana, o conversor Converter O método é chamado, onde, como o mesmo, não é chamado se eu modificar a coleção observável. O que estou perdendo??
Trechos para sua referência,
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>
Código por trás do 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();
}
}
Solução
Eu acho o conversor em um Binding
é sempre chamado se o Binding
A fonte foi atualizada e notifica sobre essa atualização (como um DependencyProperty
ou usando INotifyPropertyChanged
). No entanto, um ObservableCollection
não levanta o PropertyChanged
evento se um item foi adicionado ou removido, mas eleva o CollectionChanged
evento. Não levanta nenhum evento se um item da coleção for alterado. Mesmo que o próprio item aumente PropertyChanged
, isso não vai atualizar o Binding
na coleção desde o Binding
A fonte não é o item, mas a coleção.
Temo que sua abordagem não funcione dessa maneira. Você poderia se ligar diretamente a ObservableCollection.Count
e adicione um conversor de matemática apropriado a ele para realizar a inversão e multiplicação, mas o Count
A propriedade não realiza notificação de alteração, portanto, essa não é uma opção. Eu acho que você terá que fornecer outra propriedade em seu viewmodel ou código-behind que lida com esses casos ...
Outras dicas
Um conversor multibinding pode ser usado para superar esse problema. Em seguida, você pode vincular à propriedade Coleção.Count e à coleção ao mesmo tempo. A contagem acionará a ligação para ser reavaliada e você usa a segunda ligação para realmente transformar os valores conforme necessário
<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>
Um conversor é chamado quando a ligação acontece ou a propriedade muda. Portanto, seu conversor é chamado para o seu booleano sempre que o valor das mudanças booleanas. Sua coleção é definida uma vez e é quando a ligação ocorre e o conversor é usado. Quando os internos da coleção mudam (a coleção é adicionada ou removida), a propriedade não muda (ou seja, você não está vinculando uma nova coleção) para que seu conversor não atire novamente.
Use um modelo de exibição e envolva sua coleção e adicione outra propriedade, como a contagem que implementa a notificação de alteração. Você pode usar esta classe de wrapper de aqui que embrulhará sua coleção e será fácil adicionar uma propriedade lá.