2010-09-22 1 views
8

Ho un con la proprietà IsChecked associata a una proprietà utilizzando un binding OneWay.OneWay vincolante per la proprietà IsChecked di ToggleButton in WPF

<ToggleButton 
    Command="{Binding Path=SomeCommand}" 
    IsChecked="{Binding Path=SomeProperty, Mode=OneWay}" /> 

Il SomeCommand alterna il valore booleano SomeProperty, e un evento PropertyChanged viene sollevata per SomeProperty.

Se cambio SomeProperty nel mio modello di visualizzazione, ToggleButton si preme correttamente. Tuttavia, se faccio clic su ToggleButton l'associazione sembra essere persa e il pulsante non viene più controllato in base al valore di SomeProperty. Qualche idea su come risolvere questo problema?

+0

Cosa fa il tuo SomeCommand? Ho un numero di ToggleButtons che fanno la stessa cosa, con lo stesso tipo di binding, e tutti SomeCommand fa negare il valore corrente di SomeProperty. –

+0

SomeProperty era in realtà un tipo diverso e stavo usando un convertitore per cambiarlo in un booleano. L'ho lasciato fuori per rendere la domanda più semplice. –

risposta

4

Questo è di progettazione quando si utilizza il collegamento dati oneway. Aggiungi la proprietà allegata PresentationTraceSources.TraceLevel = Alta alla tua associazione e vedrai quando verrà disconnessa. Questo collegamento descrive anche il problema (senza offrire alcuna soluzione): Debugging Data Binding in WPF

Il modo in cui normalmente lo risolvo è utilizzare un comando per l'interazione dell'utente e il codice dietro per modificare l'aspetto del controllo a causa di alcune proprietà modificate.

+0

Perché questa risposta è stata accettata? Non risolve il problema (che esiste e può essere facilmente riprodotto). – Sinatr

0

Penso che il problema si riduce a un conflitto tra il comando e il binding IsChecked. La mia soluzione è stata quella di cambiare il mio viewmodel per esporre uno bool? e associarlo alla proprietà IsChecked. Non ho associato un comando allo ToggleButton. Altrove nel mio codice in cui voglio commutare la proprietà io uso SomeCommand.

10

C'è un modo semplice ed elegante per risolvere il problema del manifesto originale - sostituire beni IsChecked del ToggleButton con una proprietà attaccabile che fisserà IsChecked del pulsante nel suo gestore cambiamento:

namespace TBFix 
{ 
    public class TBExtender 
    { 
    public static readonly DependencyProperty IsCheckedProperty = 
     DependencyProperty.RegisterAttached("IsChecked", 
              typeof(bool), 
              typeof(TBExtender), 
              new PropertyMetadata(OnChanged)); 

    public static bool GetIsChecked(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(IsCheckedProperty); 
    } 
    public static void SetIsChecked(DependencyObject obj, bool value) 
    { 
     obj.SetValue(IsCheckedProperty, value); 
    } 

    private static void OnChanged(DependencyObject o, 
            DependencyPropertyChangedEventArgs args) 
    { 
     ToggleButton tb = o as ToggleButton; 
     if (null != tb) 
     tb.IsChecked = (bool)args.NewValue; 
    } 
    } 
} 

XAML poi sarà simile a questa:

<ToggleButton Command="{Binding Path=SomeCommand}" 
       TBFix:TBExtender.IsChecked="{Binding Path=SomeProperty, 
                Mode=OneWay}" /> 

EDIT: la soluzione OP non funziona, perché quando si preme il pulsante la proprietà IsChecked si trova nel codice (questo è il modo MS implementato controllo ToggleButton) - impostando la proprietà rimuove il vincolante om it e quindi smette di funzionare.

Utilizzando la proprietà associata, è possibile risolvere questo problema perché non viene mai assegnato un valore nel codice e pertanto i binding rimangono intatti.

+0

Ciao Alex, Grazie per aver fornito l'elegante soluzione, funziona per me. ma non capisco come funziona Puoi spiegare un po 'di più? –

+0

Ho aggiunto poche parole sull'idea alla base della mia soluzione. Puoi leggere ulteriori informazioni sulle proprietà collegate su MSDN (http://msdn.microsoft.com/en-us/library/vstudio/ms749011(v=vs.100).aspx) –

+0

Questo è davvero elegante! – akshay2000

1

Ho un problema simile.

Non è "il legame sembra perdersi" (a meno che non si tratta di precedenti quadri problemi). Il binding continua a funzionare e può essere facilmente provato modificando la proprietà al di fuori di che comanda il (ad esempio nel gestore di un altro clic sull'evento/comando del pulsante).

Il problema è quello IsChecked possono essere modificate in due modi: 1) leganti (quando il valore di SomeProperty è pulsante modificato viene aggiornato 2) utenti (se utente preme il pulsante che cambi IsChecked, ma legame è OneWay così SomeProperty sarà non essere aggiornato).

Così potrebbe essere desincronizzazione si verifica quando SomeProperty == false ma pulsante IsChecked == true o viceversa.

Per ottimizzare le prestazioni, il meccanismo di associazione sta verificando se il nuovo valore è diverso da quello corrente. Quindi, se si verifica desincronizzazione e si tenta di aggiornare SomeProperty con il valore che ha già, quindi non accadrà nulla.

soluzione è semplice: struttura aggiornamento a 2 passi

SomeProperty = !set; 
SomeProperty = set; 

dove set è il valore necessario (ad esempio opposta alla corrente SomeProperty).

0

Per quanto ne so Sinatr ha ragione riguardo al "desync" che si verifica, almeno nei quadri più recenti.

Un altro modo semplice per risolvere il problema è rimuovere la modalità = oneway e implementare un setter vuoto. Es:

bool _MyIsEnabled; 
    public bool MyIsEnabled 
    { 
     get { return _MyIsEnabled; } 
     set { } 
    } 

Con questa impostazione di legame si è possibile modificare il valore della variabile supporto dal vostra funzione di legame di comando, o da se è necessario. Basta ricordare di chiamare RaisePropertyChanged.