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();
    }
}   
Foi útil?

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á.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top