WPF динамически загружает xaml с правилами валидации

1

Я относительно новичок в WPF, и у меня возникла проблема.
Я должен реализовать форму, которая получает UI (xaml) из базы данных (как и данные). Каждая из этих форм, которая будет создана во время выполнения, будет иметь разные элементы управления.
Хотя я не согласен с этим подходом, я должен следовать указаниям моего начальника.
Проблема заключается в проверке.
Мы решили сделать это с Правилами валидации.
Поэтому я попытался реализовать основной пример с помощью 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>

Ошибка, которую я получаю при загрузке xaml

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

И в этой строке:

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

Примечание: c определяется как:

xmlns:c="clr-namespace:WpfDynamicTest1"

Как я могу преодолеть эту ошибку?
Я столкнулся с подобными ошибками с ControlTemplate и Style для ошибок, но я переместил их в Application.xaml, и мои проблемы были решены.
Могу ли я сделать что-то подобное со ссылкой на класс?

Изменение: Дополнительная информация: Как загрузить xaml:
Форма "ячейки" имеет следующие свойства:

 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

Поэтому, когда я вызываю форму, я делаю это:

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

Загружается функция FormCharacteristics для заполнения msUI и UI.

  • 0
    Вы уверены, что ValidationRule "AgeRangeRule" правильно определен в пространстве имен с именем WpfDynamicTest1?
  • 0
    Да, если я не загружаю xaml из БД во время выполнения и работаю как обычно, код работает
Теги:
wpf

2 ответа

1
Лучший ответ

Хотя не уверен, что вы просматриваете некоторые из следующих ссылок, но я надеюсь, что они могут вам помочь:

Компиляция/выполнение XAML во время выполнения программы

WPF - динамически компилирует и запускает обработчики событий в свободном XAML, используя CodeDom

Загрузка XAML во время выполнения?

Ошибка: "Невозможно создать неизвестный тип" {clr-namespace: NameSpace.Properties} Настройки '.'

РЕДАКТИРОВАТЬ

Основываясь на ссылках выше, если вы используете XamlReader, я создал образец и его работу. В этом случае причина, по которой я нашел, для XAML Parser нуждается в ParserContext для сопоставления пространств имен для привязки требуемых типов во время выполнения.

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>

Код позади (С#)

  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());
            }
        }
    }

Заметка

Для проверки привязки. Я использовал тот же код MSDN, который вы предоставили.

Кроме того, поскольку я не с VB.NET HAT сейчас, я выбираю С# для кода позади !! Хотя код достаточно прост.

  • 0
    @Nianios Что произойдет, если вы измените: xmlns: c = "clr-namespace: WpfDynamicTest1" На xmlns: c = "clr-namespace: WpfDynamicTest1; сборка: WpfDynamicTest1OrWhatEverAssemblyItIsIn"
  • 0
    Хм, я кодирую в VB, и когда я добавляю это, я получаю много ошибок. Первым является URI "clr-namespace: BindValidation; Assembly: BindValidation", который не является допустимым идентификатором пространства имен.
0

Ваш AngeRangeRule должен быть получен из ValidationRule.

public class AgeRangeRule: ValidationRule {.... }

И вы должны переопределить член ValidationResult:

public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        // Cast value object and check if it is valid
        return new ValidationResult(...,...);
    }
  • 0
    Это не имеет отношения к вопросу. Я последовал примеру. Так что я сделал все это. Теперь я пытаюсь загрузить XAML во время выполнения.
  • 0
    Странный. Я действительно пытался иметь класс AgeRangeRule и я получил ошибку, которую вы имели. И когда я извлек его из ValidationRule и реализовал Validate , ваш пример кода работал нормально.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню