2017-02-02 6 views
0

Я создаю окно, состоящее из динамически созданных элементов управления. Я создаю их с помощью ItemsControl:Проверка динамически созданного элемента структуры WPF

<ItemsControl Grid.Row="0" Name="DynamicContent" ItemsSource="{Binding Path=EmbeddedInputControls}" ItemTemplateSelector="{Binding Path=EmbeddedInputControlsTemplateSelector}"> 
     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <WrapPanel Orientation="Horizontal"/> 
      </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
</ItemsControl> 

Если ItemTemplateSelector выбирает DataTemplate в зависимости от типа от ресурсов:

<Window.Resources> 
    <converters:ErrorBooleanToBrush x:Key="ErrorBooleanToBrush"/> 
    <DataTemplate x:Key="EmbeddedStringInput" DataType="embeddedInputDescriptors:StringEmbeddedInputDescriptor"> 
     <StackPanel Orientation="Horizontal" Background="{Binding IsErrored, Converter={StaticResource ErrorBooleanToBrush}}"> 
     <Label Content="{Binding LabelContent}"></Label> 
     <dxe:TextEdit EditValue="{Binding TextValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="{Binding IsReadOnly}" /> 
     </StackPanel> 
    </DataTemplate> 
    <DataTemplate x:Key="EmbeddedIntegerInput" DataType="embeddedInputDescriptors:IntegerEmbeddedInputDescriptor"> 
     <StackPanel Orientation="Horizontal" Name="IntStackPanel"> 
      <Label Content="{Binding LabelContent}"></Label> 
      <dxe:SpinEdit Value="{Binding IntValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="{Binding IsReadOnly}" 
         MinValue="{Binding MinValue}" MaxValue="{Binding MaxValue}" Validate="OnValidate" Tag="{Binding Self}"/> 
     </StackPanel> 
    </DataTemplate> 
</Window.Resources> 

Это прекрасно работает для отображения, но проверки, оказалось, головная боль. Решение, которое я наконец нашел использует код-сзади и обработчик события OnValidate:

private void OnValidate(object sender, ValidationEventArgs e) 
{ 
    var dynamicInputElement=((FrameworkElement)sender).Tag as IEmbeddedInputDescriptor; 

    var errorContent = dynamicInputElement?.ErrorContent(e.Value); 

    if(!string.IsNullOrEmpty(errorContent)) 
    { 
     e.IsValid = false; 
     e.ErrorContent = errorContent; 
    } 
} 

Это единственный код, за что я должен был написать, и я хотел бы избавиться от него, но я просто не могу Посмотрите, как реализовать проверку без него. Правила проверки основаны на бизнес-логике, поэтому я не могу их использовать в XAML. Я почти получил решение, когда я дал каждому DataTemplate стиля, члены которого были получены из соответствующего дескриптора, но это было немного уродливым:

{Binding IsErrored, Converter={StaticResource ErrorBooleanToBrush}} 
<StackPanel.Style> 
    <Style> 
    <Style.Triggers> 
     <DataTrigger Binding="{Binding Path=IsErrored}" Value="True"> 
       <Setter Property="StackPanel.Background" Value="LightCoral"> 
        </Setter> 
     </DataTrigger> 
     </Style.Triggers> 
    </Style> 
</StackPanel.Style> 

объектов, используемых для вывода элементов каркаса являются:

internal interface IEmbeddedInputDescriptor 
{ 
    bool IsReadOnly { get; } 
    bool IsRequired { get; } 
    object Value { get; } 
    bool IsErrored { get; } 
    string ErrorContent(object value); 
} 

Было бы неплохо избавиться от кода, и я уверен, что в этом процессе я узнаю более полезный материал о WPF.

Дополнительная информация: Re связывающих валидаций:

<dxe:SpinEdit Value="{Binding IntValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidationRules={Binding valRules}}" 

и

public IEnumerable<ValidationRule> valRules 
{ 
    get { throw new NotImplementedException(); } 
} 

Результаты в ошибке «A 'Binding' не может быть использована в пределах 'коллекции ValidationRuleCollection'. «Связывание» может быть установлено только на DependencyProperty объекта DependencyObject. '.

У меня также были проблемы с IDataErrorInfo. Мне никогда не удавалось получить либо свойство, которое будет называться, будь я его реализовано в моей главной модели просмотра или в самих дескрипторах. Возможная проблема заключается в том, чтобы определить, как определить свойство ошибки, поскольку я подозреваю, что это всегда будет «Значение», которое неоднозначно. На самом деле это была проблема с большинством решений, которые дали событие, на которое я мог ответить, оставив меня без контекста для работы.

Вот почему мое текущее решение прибегает к использованию свойства Tag. Без этого трудно связать событие формы с базовым бизнес-объектом.

+0

Я думаю, что вы можете искать ['Binding.ValidationRules'] (https://msdn.microsoft.com/en-us/library/ms753962%28v=vs.110%29.aspx?f=255&MSPPError= -2147217396). Вы можете установить это в 'DataTemplate'. Есть еще код C#, но он учитывается MVVMish способом. Вы также можете посмотреть ['IDataErrorInfo'] (http://stackoverflow.com/questions/14023552/how-to-use-idataerrorinfo-error-in-a-wpf-program), который ставит проверку в моделях viewmodels. –

+0

[«Я сломал пример кода!»] (Http: //i1.kym-cdn.com/photos/images/facebook/001/016/682/379.jpeg) ОК. «И теперь это не сработает!» Да, это обычный результат. Что еще я могу вам помочь? –

+0

Э? Что вы предлагаете сейчас? Мне лучше делать что-то, чем читать бессмысленные сообщения. –

ответ

1

Ответ оказывается связанным с тем, как я реализовал свои классы дескрипторов (объекты, которые становятся datacontext для каждого созданного элемента структуры). Я реализовал IDataErrorInfo в «неправильном» базовом классе, который он имел в виду, не был виден в иерархии классов. Свежими глазами после хорошего ночного сна я заметил это почти сразу.

Так часто бывает.

Смежные вопросы