5

Ho un ObservableCollection legato a una casella di lista e un valore booleano proprietà legato a un pulsante . Ho quindi definito due convertitori, uno che opera sulla raccolta e l'altro opera sulla proprietà booleana. Ogni volta che modifico la proprietà booleana, viene chiamato il metodo Convert del convertitore, dove lo stesso non viene chiamato se modifico la raccolta osservabile. Cosa mi manca ??Quando sarà il metodo Convert del ValueConverter essere chiamato in WPF

Frammenti per il vostro riferimento,

XAML snipet,

codice
<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> 

dietro frammento

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(); 
    } 
} 

risposta

11

credo che il convertitore in un Binding viene sempre chiamato se la fonte Binding è stata aggiornata e notifica l'aggiornamento (come DependencyProperty o INotifyPropertyChanged). Tuttavia, un ObservableCollection non solleva l'evento PropertyChanged se un elemento è stato aggiunto o rimosso, ma solleva l'evento CollectionChanged. Non genera alcun evento se viene modificato un elemento nella raccolta. Anche se l'elemento stesso solleva PropertyChanged, questo non aggiornerà lo Binding sulla raccolta poiché la sorgente Binding non è l'elemento, ma la raccolta.

Temo che il tuo approccio non funzionerà in questo modo. È possibile eseguire il binding direttamente a ObservableCollection.Count e aggiungere ad esso un convertitore matematico appropriato per eseguire l'inversione e la moltiplicazione, ma la proprietà Count non esegue la notifica di modifica, quindi questa opzione non è disponibile. Penso che dovrai fornire un'altra proprietà nel tuo ViewModel o code-behind che gestisce questi casi ...

+0

Ogni volta che un elemento viene aggiunto alla raccolta, il membro ObservableCollection è alzando CollectionModified evento. Dove i convertitori vengono attivati ​​solo quando la proprietà viene modificata. Come soluzione alternativa, è possibile sottoscrivere l'evento modificato della raccolta e quindi generare l'evento PropertyChanged con il nome della proprietà ObservableCollection. – sudarsanyes

+0

Proprio ora ho trovato la tua risposta e anch'io ho dedotto lo stesso. – sudarsanyes

+0

La soluzione alternativa potrebbe funzionare, ma è necessario tenere presente che questa soluzione alternativa aggiornerà l'associazione completa, ovvero la raccolta verrà letta di nuovo e tutti gli elementi della raccolta verranno creati nuovamente. Almeno, questo è quello che mi aspetterei. Preferisco raccomandare il binding a una proprietà 'Count' personalizzata, ma dipende dal tuo scenario se vale la pena. – gehho

2

Un convertitore viene chiamato quando avviene l'associazione o la proprietà cambia. Quindi il tuo convertitore è chiamato per il tuo booleano ogni volta che cambia il valore del booleano. La raccolta viene impostata una volta e cioè quando si verifica l'associazione e viene utilizzato il convertitore. Quando le parti interne della raccolta cambiano (la raccolta viene aggiunta o rimossa da) la proprietà non cambia (ad esempio non si sta vincolando una nuova raccolta), quindi il convertitore non si attiva nuovamente.

Utilizzare un modello di visualizzazione e avvolgere la raccolta e aggiungere un'altra proprietà come il conteggio che implementa la notifica di modifica. Puoi utilizzare questa classe wrapper da here che avvolgerà la tua raccolta e sarà facile aggiungervi una proprietà.

11

Un convertitore multibinding può essere utilizzato per risolvere questo problema. Puoi quindi associare contemporaneamente la proprietà Collection.Count e la raccolta. Il conteggio attiverà il legame per ottenere ri-valutati e quindi si utilizza il secondo vincolante per trasformare in realtà i valori come richiesto

      <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> 
+0

Grazie per questa idea! Mentre le risposte di cui sopra non ha funzionato affatto per me, questo lo fa. Ho bisogno di modificare il mio convertitore un po 'per implementare IMultiValueConverter invece di IValueConverter, e ho bisogno di chiarire a quale indice sarà la mia collezione, ma poi andrà tutto bene. – ygoe

+0

Brillante! Quell'idea mi ha fatto risparmiare un sacco di tempo. – gbc

+0

Eccellente, grazie! – Aybe