Reputation: 1426
I am relatively new in WPF and I face a problem.
I have to implement a form that gets the UI(xaml) from the database (as also the data).
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.
<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
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:
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.
Can I do something similar with the reference to the class?
Edit: Additional Info:
How I load the 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.
Upvotes: 1
Views: 2934
Reputation: 3502
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
WPF – dynamically compile and run event handlers within loose XAML using CodeDom
Error: 'Cannot create unknown type '{clr-namespace:NameSpace.Properties}Settings'.'
EDIT
Based on the links above, assuming you are using XamlReader, I created a sample and its working fine. 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 (Dynamic usercontrol to load)
<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#)
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.
Also since I am not with the VB.NET HAT now, I choose C# for the code behind!! Though the code is simple enough.
Upvotes: 1
Reputation: 1258
Your AngeRangeRule should derive from ValidationRule.
public class AgeRangeRule : ValidationRule
{
....
}
And you have to override ValidationResult
member:
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
// Cast value object and check if it is valid
return new ValidationResult(...,...);
}
Upvotes: 0