Avoiding collision of multifunctional converters in WPF code

I am creating WPF elements dynamically in the code behind, and for each row in the Grid me Grid it consists of a CheckBox and a dynamic number of TextBoxes . The necessary interaction is as follows:

  • If all TextBoxes in the row are set to 0 , set the CheckBox IsChecked property to true and disable it.
  • If one of the TextBoxes then changes from 0 , enable CheckBox and set IsChecked to false .
  • If the user clicks on CheckBox , set all related TextBoxes to 0 and disable CheckBox

I was able to execute the first part of the last using this code:

 Binding setScoreToZeroIfIsNormalChecked = new Binding("IsChecked"); setScoreToZeroIfIsNormalChecked.Source = this.NormalCheckBoxControl; setScoreToZeroIfIsNormalChecked.Converter = m_NormalCheckBoxJointScoresConverter; tempJointScoreControl.JointScoreContainer.SetBinding(ContainerBase.SingleAnswerProperty, setScoreToZeroIfIsNormalChecked); 

and converter:

 public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value is bool && targetType == typeof(Answer)) { if ((bool)value) { Answer answer = new Answer(); answer.Value = "0"; answer.DisplayValue = "0"; return answer; } else return null; } else { return null; } } 

However, trying to create another converter for implementing other functions, I ran into problems when the converters step on each other, since all functions are based on the CheckBox.IsChecked property.

Is there a way to accomplish all of the above with one or two multi-linking converters? I really would like to avoid creating a whole bunch of events and supporting them to do this.

+6
source share
2 answers

It is relatively easy. Everything should be resolved around the CheckBox IsChecked property. For a simple reason, this is a two-way property. Therefore, either you can change it, or CheckBox can change it.

So what you do, you are using MultiBinding, as such:

  MultiBinding multiBinding = new MultiBinding(); multiBinding.Converter = multiBindingConverter; multiBinding.Bindings.Add(new Binding("Text") { Source = txtbox1}); multiBinding.Bindings.Add(new Binding("Text") { Source = txtbox2}); multiBinding.NotifyOnSourceUpdated = true;//this is important. checkBox.SetBinding(CheckBox.IsCheckedProperty, multiBinding); 

And in your MultiBindingConverter you will have the value of the object [] as the first parameter that you need to convert to IList and iterate over it && & do your calculations if you must either return true / false. (IsChecked = true or false)

Now bind the CheckBox IsEnabled property to the CheckBox IsChecked property and use the BooleanInverterConverter. (If CheckBox is installed, it must be disabled and vice versa)

The final step is to get TextBoxes to listen on the actual IsChecked CheckBox property. If it is TRUE, they all must show the value 0, otherwise they can show what they want.

So create a new MultiBinding.

  MultiBinding multiBinding = new MultiBinding(); multiBinding.Converter = textboxMultiBindingConverter; multiBinding.Bindings.Add(new Binding("IsChecked") { Source = checkbox1}); multiBinding.Bindings.Add(new Binding("Text") { Source = textbox1}); multiBinding.NotifyOnSourceUpdated = true;//this is important. textbox1.SetBinding(TextBox.Text, multiBinding); 

The idea in textboxMultiBindingConverter is to either return the text (value [1]) if the value is [0] == FALSE or "0" if the value is [0] == TRUE.

+10
source

This problem can be solved very easily if you use MVVM.

You will have a ViewModel representing a row in the grid. It will have a property for each text field and one for the check box.

In addition, you will have a ViewModel for the view containing the Grid, and this ViewModel will display a collection of ViewModels rows.

ViewModel for your line:

 public class AnswersViewModel : ViewModelBase // From MvvmLight { public bool IsAnswered { get { return _isAnswered; } set { if(value == _isAnswered) return; _isAnswered = value; if(_isAnswered) { Answer1 = "0"; Answer2 = "0"; } RaisePropertyChanged("IsAnswered"); } } public string Answer1 { get { return _answer1; } set { if(value == _answer1) return; _answer1 = value; RaisePropertyChanged("Answer1"); if(_answer1 == "0" && _answer2 == "0") { _isAnswered = true; RaisePropertyChanged("IsAnswered"); } } } // The implementation of Answer2 is similar to Answer1 } 

ViewModel for view:

 public class FooViewModel : ViewModelBase { public ObservableCollection<AnswersViewModel> Answers { get { return _answers; } } } 

Your view will contain a grid with ItemsSource="{Binding Answers}" and a checklist for items that are bound to the AnswersViewModel properties.

Disable CheckBox, with which I could work through a trigger in style.

+1
source

Source: https://habr.com/ru/post/923395/


All Articles