There is a data template. It binds data from a certain class containing the properties Name, Symbol, Value, Min, Max and Dimension. Binding of the first three properties is successful. Problems begin when using validation and a converter, as shown in the code. As I believe, the Xaml parser looks for the Min, Max and Dimension properties among the Value properties, and it is a string. Consequently, in Min, Max and Dimension drops Null. I tried to solve this problem by playing with RelativeSource, but to no avail. Any ideas?

<DataTemplate> <Border> <WrapPanel> <TextBlock Width="430" Height="30" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> <TextBlock Width="60" Height="30" Text="{Binding Symbol, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> <TextBox Width="100" Height="30"> <Binding Path="Value" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <calc:VarValidation> <calc:VarValidation.Params> <calc:ValidationParams Min="{Binding Min}" Max="{Binding Max}" /> </calc:VarValidation.Params> </calc:VarValidation> </Binding.ValidationRules> <Binding.Converter> <measuring:TemperatureConvert > <measuring:TemperatureConvert.myParameter> <Binding Path="Dimension" RelativeSource="{RelativeSource Mode=TemplatedParent}" diag:PresentationTraceSources.TraceLevel="High" /> </measuring:TemperatureConvert.myParameter> </measuring:TemperatureConvert> </Binding.Converter> </Binding> </TextBox> </WrapPanel> </Border> </DataTemplate> 

As I understand it, the author of the article using this design

 <Window.Resources> <FrameworkElement x:Key="DataContextBridge" /> </Window.Resources> <Window.DataContext> <Binding Mode="OneWayToSource" Path="DataContext" Source="{StaticResource DataContextBridge}" /> </Window.DataContext> 

resets the root element of the data context into the data context of a certain FrameworkElement, after which it takes the data for the target element from the created FrameworkElement. But to assign a data context, it uses code:

 this.DataContext = nums; 

Can I do the same with Xaml markup? This is necessary because in my case a data template is used, the elements of which are repeated on the form many times, therefore, they do not have a name by which you can refer to the target element. And without explicitly setting the data context, it is null.

 <TextBox.Resources> <FrameworkElement x:Key="DataContextBridge" /> </TextBox.Resources> <TextBox.DataContext> <!-- Π—Π΄Π΅ΡΡŒ null. Как ΠΈΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ? --> <Binding Mode="OneWayToSource" Path="DataContext" Source="{StaticResource DataContextBridge}" /> </TextBox.DataContext> 
  • And so you tried: <TextBox Width = "100" Height = "30"> <TextBox.Text> <Binding Path = "Value" UpdateSourceTrigger = "PropertyChanged"> ...? - VladD
  • What do you have in mind? Value works without problems, and the update trigger is set to PropertyChanged, I just dropped it for short. - maestro

3 answers 3

The only right decision found here . Earned almost immediately. Only slightly changed the markup code.

 <Window.Resources> <my:DataResource x:Key="max" BindingTarget="{Binding Max}"/> <my:DataResource x:Key="min" BindingTarget="{Binding Min}"/> </Window.Resources> <TextBox> <TextBox.Text> <Binding UpdateSourceTrigger="PropertyChanged" Path="Value"> <Binding.ValidationRules> <my:IntValidationRule ValidatesOnTargetUpdated="True" Min="{Binding Source={StaticResource min}, Path=BindingTarget}" Max="{Binding Source={StaticResource max}, Path=BindingTarget}"> </my:IntValidationRule> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> 
  • @Alouette: Yeah. This decision was in the comments on the article on my link. - VladD

And why not just transfer the check to the data class? For example:

 public class MyClass { private int _dimension; public string Name { get; set; } public string Symbol { get; set; } public int Min { get; set; } public int Max { get; set; } public int Dimension { get { return _dimension; } set { if(value>Max||value<Min) throw new ArgumentException("ПолС Dimention Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ большС ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌΠ° Π½ΠΎ мСньшС максимума"); _dimension = value; } } } 

Then the markup will be smaller:

 <TextBox Width="100" Height="30" Text="{Binding Dimension, Mode=TwoWay, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}"/> 
  • For example, because it is not a matter of business logic, be aware of the presence of a UI and set properties specifically for display. - VladD
  • Well, it is not necessary to make such changes to the data model. You can make a view model as a model wrapper, and set validation rules there. And the model does not suffer, and there is no excess in the markup, and there is no need to write a bunch of validation rules. And there and to MVVM is not far. - Pleshkov Ivan
  • @Pleshkov Ivan: I am personally opposed to the fact that VM knows about View (and accordingly sets validation rules for it), although, of course, the question is debatable. I usually have business logic at the VM level, and all the code responsible for the mapping is carried away in View. Otherwise, two levels of logic are responsible for the mapping - is it too much honor? - VladD
  • @Pleshkov Ivan Your decision seems to lie on the surface. But @VladD correctly said: no need to do the logic and display together. In addition, when generating an unhandled exception, a dialog box with an error text is displayed, and validation avoids this, with the target input field highlighted in red. Although you can try to make your way converter. - maestro
  • @Alouette, about exceptions - I agree. I do not really like the approach with exceptions. I try to do an implementation of IDataError or INotifyDataError. And there are no exceptions, and converters and validators are not needed. As for the logic: the books and articles that I read indicate that the ViewModel is the logic of the presentation level, and it is really inappropriate to stack the logic of the model (business logic) into it. But in very simple projects, I consider it possible to combine business logic with presentation logic. In complex - I transfer the business logic to the model. This is a topic of many holivars and personal or corporate preferences. - Pleshkov Ivan

No, you cannot set a binding to an object parameter in this way. To begin with, you had to do TemperatureConvert DependencyObject , th, right? This is not very good, the converter is not. And even if you forced it to compile, it will not work anyway, since updating the properties through Binding passes only for the elements of the visual tree, and neither TemperatureConvert nor its parameter is such. Surely you get warnings like

Cannot find governing FrameworkElement or FrameworkContentElement for target element ...

in the Output window.

Try to make TemperatureConvert IMultiValueConverter and put MultiBinding for it.


However, maybe this will help: http://www.codeproject.com/Articles/18678/Attaching-a-Virtual-Branch-to-the-Logical-Tree-in

  • See Update. - maestro