Cómo enlazar propiedades booleanas inversas en WPF?

Lo que tengo es un objeto que tiene una propiedad IsReadOnly . Si esta propiedad es verdadera, me gustaría establecer la propiedad IsEnabled en un Botón, (por ejemplo), en falso.

Me gustaría creer que puedo hacerlo tan fácilmente como IsEnabled="{Binding Path=!IsReadOnly}" pero eso no funciona con WPF.

¿Estoy relegado a tener que pasar por todas las configuraciones de estilo? Simplemente parece demasiado prolijo para algo tan simple como establecer un bool en el inverso de otro bool.

  

Puede usar un ValueConverter que invierta una propiedad bool por usted.

XAML:

 IsEnabled="{Binding Path=IsReadOnly, Converter={StaticResource InverseBooleanConverter}}" 

Convertidor:

 [ValueConversion(typeof(bool), typeof(bool))] public class InverseBooleanConverter: IValueConverter { #region IValueConverter Members public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (targetType != typeof(bool)) throw new InvalidOperationException("The target must be a boolean"); return !(bool)value; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotSupportedException(); } #endregion } 

¿Ha considerado una propiedad IsNotReadOnly? Si el objeto enlazado es un ViewModel en un dominio MVVM, entonces la propiedad adicional tiene mucho sentido. Si se trata de un modelo de entidad directo, puede considerar la composición y presentar un modelo de vista especializado de su entidad al formulario.

Con el encuadernado estándar necesitas usar convertidores que parezcan poco ventosos. Entonces, te recomiendo que mires mi proyecto CalcBinding , que fue desarrollado especialmente para resolver este problema y algunos otros. Con el enlace avanzado puede escribir expresiones con muchas propiedades de origen directamente en xaml. Diga, puede escribir algo como:

  

o

  

o

  

o

  

donde A, B, C, IsChecked – propiedades de viewModel y funcionará correctamente

¡Buena suerte!

Yo recomendaría usar https://quickconverter.codeplex.com/

Invertir un booleano es tan simple como:

Eso acelera el tiempo normalmente necesario para escribir convertidores.

Quería que mi XAML se mantuviera lo más elegante posible, así que creé una clase para envolver el bool que reside en una de mis bibliotecas compartidas, los operadores implícitos permiten que la clase se use como bool en código subyacente sin problemas

 public class InvertableBool { private bool value = false; public bool Value { get { return value; } } public bool Invert { get { return !value; } } public InvertableBool(bool b) { value = b; } public static implicit operator InvertableBool(bool b) { return new InvertableBool(b); } public static implicit operator bool(InvertableBool b) { return b.value; } } 

Los únicos cambios necesarios para su proyecto son hacer que la propiedad que desea invertir devuelva esto en lugar de bool

  public InvertableBool IsActive { get { return true; } } 

Y en el postfix XAML el enlace con Value o Invert

 IsEnabled="{Binding IsActive.Value}" IsEnabled="{Binding IsActive.Invert}" 

Este también funciona para bools nullable.

  [ValueConversion(typeof(bool?), typeof(bool))] public class InverseBooleanConverter : IValueConverter { #region IValueConverter Members public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (targetType != typeof(bool?)) { throw new InvalidOperationException("The target must be a nullable boolean"); } bool? b = (bool?)value; return b.HasValue && !b.Value; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return !(value as bool?); } #endregion } 

No sé si esto es relevante para XAML, pero en mi aplicación simple de Windows, creé el enlace manualmente y agregué un controlador de eventos de formato.

 public FormMain() { InitializeComponent(); Binding argBinding = new Binding("Enabled", uxCheckBoxArgsNull, "Checked", false, DataSourceUpdateMode.OnPropertyChanged); argBinding.Format += new ConvertEventHandler(Binding_Format_BooleanInverse); uxTextBoxArgs.DataBindings.Add(argBinding); } void Binding_Format_BooleanInverse(object sender, ConvertEventArgs e) { bool boolValue = (bool)e.Value; e.Value = !boolValue; } 

Agregue una propiedad más en su modelo de vista, que devolverá el valor inverso. Y atar eso al botón. Me gusta;

en el modelo de vista:

 public bool IsNotReadOnly{get{return !IsReadOnly;}} 

en xaml:

 IsEnabled="{Binding IsNotReadOnly"} 

Tuve un problema de inversión, pero una solución ordenada.

La motivación era que el diseñador de XAML mostraría un control vacío, por ejemplo, cuando no había datoscontext / no MyValues (itemssource).

Código inicial: oculta el control cuando MyValues está vacío. Código mejorado: mostrar control cuando MyValues NO es nulo o está vacío.

Por supuesto, el problema es cómo express ‘1 o más elementos’, que es lo opuesto a 0 elementos.

       

Lo resolví agregando:

  

Ergo establece el valor predeterminado para el enlace. Por supuesto, esto no funciona para todo tipo de problemas inversos, pero me ayudó con código limpio.

Siguiendo la respuesta de @ Paul, escribí lo siguiente en ViewModel:

 public bool ShowAtView { get; set; } public bool InvShowAtView { get { return !ShowAtView; } } 

Espero que tener un fragmento aquí ayude a alguien, probablemente novato como yo.
Y si hay un error, ¡por favor házmelo saber!

Por cierto, también estoy de acuerdo con el comentario de @heltonbiker: definitivamente es el enfoque correcto solo si no tienes que usarlo más de 3 veces …

Hice algo muy similar. Creé mi propiedad detrás de escena que permitía la selección de un cuadro combinado SÓLO si había terminado de buscar datos. Cuando aparece por primera vez la ventana, inicia un comando cargado de manera sincronizada, pero no quiero que el usuario haga clic en el cuadro combinado mientras todavía está cargando datos (estaría vacío y luego se llenaría). Entonces, por defecto, la propiedad es falsa, así que devuelvo la inversa en el getter. Luego, cuando estoy buscando, establezco la propiedad en verdadero y de regreso en falso cuando se completa.

 private bool _isSearching; public bool IsSearching { get { return !_isSearching; } set { if(_isSearching != value) { _isSearching = value; OnPropertyChanged("IsSearching"); } } } public CityViewModel() { LoadedCommand = new DelegateCommandAsync(LoadCity, LoadCanExecute); } private async Task LoadCity(object pArg) { IsSearching = true; //**Do your searching task here** IsSearching = false; } private bool LoadCanExecute(object pArg) { return IsSearching; } 

Luego, para el cuadro combinado, puedo vincularlo directamente al IsSearching: