简体   繁体   English

WPF使用验证规则动态加载XAML

[英]WPF dynamically load xaml with validation rules

I am relatively new in WPF and I face a problem. 我在WPF中相对较新,因此遇到了问题。
I have to implement a form that gets the UI(xaml) from the database (as also the data). 我必须实现一种从数据库(以及数据)中获取UI(xaml)的形式。 Each of these forms that will be created at runtime they will have different controls. 这些将在运行时创建的表单中的每一个将具有不同的控件。
Although I disagree with this approach I have to follow my boss directions. 尽管我不同意这种方法,但我必须遵循老板的指示。
The problem is with the validation. 问题在于验证。
We decided to do it with Validation Rules. 我们决定使用“验证规则”来做。
So I tried to implemented the basic example with the AgeRangeRule . 因此,我尝试使用AgeRangeRule实现基本示例。

<TextBox Name="textBox1" Width="50" FontSize="15"
     Validation.ErrorTemplate="{StaticResource validationTemplate}"
     Style="{StaticResource textBoxInError}"
     Grid.Row="1" Grid.Column="1" Margin="2">
  <TextBox.Text>
    <Binding Path="Age" Source="{StaticResource ods}"
         UpdateSourceTrigger="PropertyChanged" >
       <Binding.ValidationRules>
         <c:AgeRangeRule Min="21" Max="130"/>
      </Binding.ValidationRules>
    </Binding>
  </TextBox.Text>
</TextBox>

The error that I get when I load the xaml is 加载xaml时出现的错误是

Additional information: 'Cannot create unknown type '{clr-namespace:WpfDynamicTest1}AgeRangeRule'.' 

And is in this line: 并在此行中:

 <c:AgeRangeRule Min="21" Max="130"/>

Note: c is defined as: 注意:c定义为:

xmlns:c="clr-namespace:WpfDynamicTest1"

How can I overcome this error? 我该如何克服这个错误?
I faced similar errors with the ControlTemplate and Style for the errors but I moved them to the Application.xaml and my problems solved. 我在ControlTemplate和Style上遇到了类似的错误,但是将它们移到Application.xaml,问题解决了。
Can I do something similar with the reference to the class? 我可以对类进行类似的操作吗?

Edit: Additional Info: How I load the xaml: 编辑:附加信息:我如何加载xaml:
The "cell" form has these properties: “单元格”形式具有以下属性:

 Public Property FormId() As Integer
    Get
        Return miFormId
    End Get
    Set(ByVal value As Integer)
        miFormId = value
        FormCharacteristics(value)
    End Set
End Property

 Public Property UI() As String
    Get
        Return msUI
    End Get
    Set(ByVal value As String)
        msUI = value
        Dim rootObject As DependencyObject = XamlReader.Parse(value)
        Me.Content = rootObject
    End Set
End Property

So when I call the form I do this: 因此,当我调用表单时,我会这样做:

 Dim winD As New winDynamic
 winD.FormId = 4
 winD.Show()

The FormCharacteristics fills msUI and UI is loaded. FormCharacteristics填充msUI,并加载UI。

Though not sure if you search through some of the following links but i hope they could be of help to you: 虽然不确定您是否可以通过以下某些链接进行搜索,但我希望它们对您有所帮助:

Compile/Execute XAML during program runtime 在程序运行时编译/执行XAML

WPF – dynamically compile and run event handlers within loose XAML using CodeDom WPF –使用CodeDom在松散的XAML中动态编译和运行事件处理程序

Loading XAML at runtime? 在运行时加载XAML?

Error: 'Cannot create unknown type '{clr-namespace:NameSpace.Properties}Settings'.' 错误:“无法创建未知类型'{clr-namespace:NameSpace.Properties}设置”。

EDIT 编辑

Based on the links above, assuming you are using XamlReader, I created a sample and its working fine. 根据上面的链接,假设您使用的是XamlReader,我创建了一个示例,并且可以正常工作。 In this case, the reason I found is, the XAML Parser need the ParserContext to map the namespaces to bind the required types at run time. 在这种情况下,我发现的原因是,XAML解析器需要ParserContext来映射名称空间以在运行时绑定所需的类型。

Xaml (Dynamic usercontrol to load) Xaml(要加载的动态用户控件)

<UserControl 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="300" Width="300"
        xmlns:c="clr-namespace:WpfApplication1">
    <UserControl.Resources>
        <c:MyDataSource x:Key="ods"/>

        <ControlTemplate x:Key="validationTemplate">
            <DockPanel>
                <TextBlock Foreground="Red" FontSize="20">!</TextBlock>
                <AdornedElementPlaceholder/>
            </DockPanel>
        </ControlTemplate>
        <Style x:Key="textBoxInError" TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="true">
                    <Setter Property="ToolTip"
              Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                              Path=(Validation.Errors)[0].ErrorContent}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </UserControl.Resources>
    <StackPanel>
        <TextBox Name="textBox1" Width="50" FontSize="15"
         Validation.ErrorTemplate="{StaticResource validationTemplate}"
         Style="{StaticResource textBoxInError}"
         Grid.Row="1" Grid.Column="1" Margin="2">
            <TextBox.Text>
                <Binding Path="Age" Source="{StaticResource ods}"
             UpdateSourceTrigger="PropertyChanged" >
                    <Binding.ValidationRules>
                        <c:AgeRangeRule Min="21" Max="130"/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>

        <Button x:Name="btnDynamic" Width="150" Height="30" Content="Click Me"/>
    </StackPanel>
</UserControl>

Code behind (C#) 背后的代码(C#)

  public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            LoadXAML();
        }

        public void LoadXAML()
        {
            try
            {
                using (StreamReader xamlStream = new StreamReader(@"C:\WpfApplication1\WpfApplication1\DynamicWindow.xaml"))
                {
                    var context = new ParserContext();
                    context.XamlTypeMapper = new XamlTypeMapper(new string[] { });
                    context.XmlnsDictionary.Add("c", "clr-namespace:WpfApplication1");
                    context.XamlTypeMapper.AddMappingProcessingInstruction("clr-namespace:WpfApplication1", "WpfApplication1", "WpfApplication1");

                    string xamlString = xamlStream .ReadToEnd();

                    DependencyObject rootObject = XamlReader.Parse(xamlString, context) as DependencyObject;
                    cntControl.Content = rootObject; //cntControl is a content control I placed inside MainWindow
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }
        }
    }

Note 注意

For the Binding Validation., I used same MSDN code you provided. 对于绑定验证。,我使用了您提供的相同的MSDN代码。

Also since I am not with the VB.NET HAT now, I choose C# for the code behind!! 另外,由于我现在不使用VB.NET HAT,因此我选择C#作为后面的代码! Though the code is simple enough. 虽然代码很简单。

Your AngeRangeRule should derive from ValidationRule. 您的AngeRangeRule应该从ValidationRule派生。

public class AgeRangeRule : ValidationRule { .... }

And you have to override ValidationResult member: 而且您必须重写ValidationResult成员:

public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        // Cast value object and check if it is valid
        return new ValidationResult(...,...);
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM