0

I am trying to add a ValidationRule to XAML from code behind and and need to have this:

<TextBox.Text>
   <Binding Path="Model.txt1.Value" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
      <Binding.ValidationRules>
         <localVal:RequiredValidate />
      </Binding.ValidationRules>
   </Binding>
</TextBox.Text>

I have tried this so far:

FrameworkElement SelectedObject = fe_dragged_control;
DependencyProperty property =                           
    ControlBindingExtensions.GetDependencyPropertyFromName("Text", SelectedObject.GetType());
Binding binding = new Binding("Model." + SelectedObject.Name + ".Value");
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnDataErrors = true;
RequiredValidate role = new RequiredValidate();
binding.ValidationRules.Add(role);
SelectedObject.SetBinding(property, binding);

I found this on google, but I am getting the following result (removed irrelevant properties for readability:

<TextBox Text="{Binding ValidatesOnDataErrors=True, 
                Path=Model.txt0.Value, 
                UpdateSourceTrigger=PropertyChanged}" >

How do I get to have the the result I need (the 1st code)? Thanks

Konamiman
  • 49,681
  • 17
  • 108
  • 138
mkdavor
  • 135
  • 4
  • 16
  • ValidatesOnDataErrors is takeing care of [IDataErrorInfo](https://msdn.microsoft.com/en-us/library/system.componentmodel.idataerrorinfo(v=vs.110).aspx) not of the ValidationRules try this insted – Venson Jun 19 '15 at 11:29
  • Thanks, but I cannot use the IDataErrorInfo because in my case I need to keep the validation in the xaml. I am creating the controls dynamically as the user chooses them and he should be able to choose predefined validations, then save the grid to load it later again. – mkdavor Jun 19 '15 at 11:42
  • I do not see why you cannot use Data-binding for this case instead it was literally made for this scenario and if so you can also use the IDataErrorInfo. You create a VM that represents the Options then you bind in your XAML to it and specify a DataTemplate for the VM that shows the grid. Usual in WPF – Venson Jun 19 '15 at 11:48
  • I am not sure I understood you. Let me tell you again. I need to have dynamically created XAML. The users drags and drops controls according to their needs. Then selects validations. There is also versioning supported and if there is a new version, there might be different validations for the same XAML. I do not want to put validation rules in the DB because I would have a different row for every EDIT the user makes which in time there will be a huge amount of data in the DB. Putting ValidationRules in XAML will reduce the DB size and improve speed. – mkdavor Jun 19 '15 at 11:59
  • 2
    The code in this question looks identical to one asked two hours earlier by another user. http://stackoverflow.com/questions/30933502 – Xavier Jun 19 '15 at 12:01
  • And you may do not understand the purpose of XAML and its Templates. You thing in the way as a WinForms developer does. There is noting as you may thing of "dynamically created XAML". In XAML you create a ViewModel that acts as the DataContext for every Control in the View(XAML). Then you may have a dynamic Ammount of Controls. If this is the case (your case) you first create the DataContext that contains a !LIST! of VM's and then you bind onto the list inside you VM. This will have the "effect" of "dynamic" XAML.CodeBehind is Out in WPF and disrespects nearly ALL advantages of WPF and Binding – Venson Jun 19 '15 at 12:05

1 Answers1

4

You should check your viewmodel. Your sample worked with the following test case.

<TextBox x:Name="Txt0">

Validation

using System.Globalization;
using System.Windows.Controls;

namespace WpfApplication2
{
    public class RequiredValidate : ValidationRule
    {
        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            return value != null ? ValidationResult.ValidResult : new ValidationResult(false, "Value required");
        }
    }
}

Code behind

    private void InitializeValidation()
    {

        FrameworkElement SelectedObject = Txt0;
        DependencyProperty property =
            GetDependencyPropertyByName(SelectedObject, "TextProperty");
        Binding binding = new Binding("Model.Txt0");
        binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        binding.ValidatesOnDataErrors = true;
        RequiredValidate role = new RequiredValidate();
        binding.ValidationRules.Add(role);
        SelectedObject.SetBinding(property, binding);
    }

    public static DependencyProperty GetDependencyPropertyByName(DependencyObject dependencyObject, string dpName)
    {
        return GetDependencyPropertyByName(dependencyObject.GetType(), dpName);
    }

    public static DependencyProperty GetDependencyPropertyByName(Type dependencyObjectType, string dpName)
    {
        DependencyProperty dp = null;

        var fieldInfo = dependencyObjectType.GetField(dpName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
        if (fieldInfo != null)
        {
            dp = fieldInfo.GetValue(null) as DependencyProperty;
        }

        return dp;
    }

and ViewModels

public class MainWindowViewModel
{
    public MainWindowViewModel()
    {
        Model = new Model();
    }

    public Model Model { get; set; }
}

public class Model
{
    public Model()
    {
        Txt0 = 42;
        Txt1 = 99;
    }

    public int? Txt0 { get; set; }
    public int? Txt1 { get; set; }
}
Chui Tey
  • 5,436
  • 2
  • 35
  • 44
  • Thanks for the detailed answer, but what I really need is to save the XAML in the DB. I have this: THE XAML HERE I extract the dynamically generated XAML and save it as varchar in the DB. This method does not give me the XAML. Do you know how do I get the have xaml generated like the one I need (int the question) – mkdavor Jun 19 '15 at 12:46
  • 1
    I'd hesitate to reverse engineer any XAML from an existing visual tree. Why not just concatenate strings? – Chui Tey Jun 19 '15 at 12:52
  • I reverse engineer the XAML using classes provided by some user on code project. The classes work great and precise. The problem is the ValidationRules binding. Is there another way to bind a ValidationRule to the XAML so I get the desired output above? – mkdavor Jun 19 '15 at 13:01
  • Code Project article: http://www.codeproject.com/Articles/569753/WPF-Form-Designer-Prototype-MVVM There is a link for the demo. Download it, click add row, drag and drop something and click serialize. That gets the XAML. I cannot seem to create the xaml from code behind (The binding I am talking about). Getting the xaml is done with this. Thanks again for trying to help. – mkdavor Jun 19 '15 at 13:20
  • I'm going to vote down the question as it is irrelevant to your problem. You are experiencing a problem with the XAMLWriter class that AlexDov wrote. You need to step through the code, figure what problem it is and make it a smaller, focussed question on StackOverflow. Hint: the XAMLWriter probably did not walk through a Binding's Validations collection. – Chui Tey Jun 19 '15 at 20:52