Я создаю окно, состоящее из динамически созданных элементов управления. Я создаю их с помощью 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. Без этого трудно связать событие формы с базовым бизнес-объектом.
Я думаю, что вы можете искать ['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. –
[«Я сломал пример кода!»] (Http: //i1.kym-cdn.com/photos/images/facebook/001/016/682/379.jpeg) ОК. «И теперь это не сработает!» Да, это обычный результат. Что еще я могу вам помочь? –
Э? Что вы предлагаете сейчас? Мне лучше делать что-то, чем читать бессмысленные сообщения. –