2013-10-03 4 views
2

У меня есть пользовательский элемент управления, у которого есть текстовое поле, где его свойство text привязано к свойству зависимостей, называемому SelectedValue. Когда пользователь вводит текст, это значение проверяется против другого DP, называемого ItemsSource, чтобы узнать, есть ли он там. Если нет, я выдаю ошибку. Все работает - TB в UC имеет по умолчанию красный квадрат вокруг него, когда есть ошибка.Binding Validation.ErrorTemplate в UserControl

Но я хотел бы, чтобы пользователь мог указать ControlTemplate в XAML при создании экземпляра UC. Поэтому я подумал, что могу создать еще один DP типа ControlTemplate, с которым они могли бы связываться. Кажется, это работает, но как я могу реализовать это в XAML? Если это что-то вроде: «Свойство„ErrorTemplate“не может быть с привязкой к данным»

Validation.ErrorTemplate="{Binding ValidationTemplate}" 

он бросает ошибку говоря. Ниже приведены соответствующие части кода:

<Canvas DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"> 
    .... 
    <TextBox x:Name="ValueTextBox" 
      TextWrapping="NoWrap" 
      GotFocus="_ValueTextBox_GotFocus" 
      Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Canvas}}, Path=ActualWidth}" 
      Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Canvas}}, Path=ActualHeight}" 
     ----->Validation.ErrorTemplate="{Binding ValidationTemplate}"<----- 
      > 

     <TextBox.Resources> 
      <CollectionViewSource x:Key="UniqueNamesList" Source="{Binding ItemsSource}" /> 
     </TextBox.Resources> 

     <TextBox.Text> 
      <Binding Path="SelectedValue" > 
       <Binding.ValidationRules> 
        <l:InListValidator ValidationStep="RawProposedValue" 
             IgnoreCase="True" 
             UniqueNames="{StaticResource UniqueNamesList}" /> 
       </Binding.ValidationRules> 
      </Binding> 
     </TextBox.Text> 
    </TextBox> 
    .... 
</Canvas> 

и сама DP:

public object ValidationTemplate 
{ 
    get { return (ControlTemplate)GetValue(ValidationTemplateProperty); } 
    set { SetValue(ValidationTemplateProperty, value); } 
} 
public static readonly DependencyProperty ValidationTemplateProperty = 
    DependencyProperty.Register("ValidationTemplate" 
           , typeof(ControlTemplate) 
           , typeof(AutoCompleteComboBox) 
           , new FrameworkPropertyMetadata(new ControlTemplate())); 

Спасибо за любую помощь.

Эрни


Update:

Спасибо парни. Я действительно пробовал ответы Ади и Нита. Оба работали, но Ади был ближе к тому, что я искал, не имея необходимости определять шаблон, локальный для User Control. Nit фактически работает, даже если я на самом деле не создаю шаблон и просто добавляю привязку, но дизайнер дает ошибку. Мне пришлось немного настроить код Ади, чтобы установить его на самом текстовом поле:

public ControlTemplate ValidationTemplate 
{ 
    get { return (ControlTemplate)GetValue(ValidationTemplateProperty); } 
    set { SetValue(ValidationTemplateProperty, value); } 
} 
public static readonly DependencyProperty ValidationTemplateProperty = 
    DependencyProperty.Register("ValidationTemplate" 
           , typeof(ControlTemplate) 
           , typeof(AutoCompleteComboBox) 
           , new FrameworkPropertyMetadata(new ControlTemplate(), OnValidationTemplateChanged)); 

private static void OnValidationTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    if (e.NewValue != null) 
    { 
     AutoCompleteComboBox control = (AutoCompleteComboBox)d; 
     Validation.SetErrorTemplate(control.ValueTextBox, (ControlTemplate)e.NewValue); 
    } 
} 

Спасибо!

ответ

3

Глядя на Validation.ErrorTemplate MSDN page, вы можете видеть, что оно имеет свойство метаданных IsNotDataBindable, равное true, так что, к сожалению, вы не можете привязать данные к этому свойству.

Я считаю, что вы все еще можете обрабатывать OnChanged события вашего свойства зависимостей, чтобы установить это свойство самостоятельно с Validation.SetErrorTemplate():

public static readonly DependencyProperty ValidationTemplateProperty = 
    DependencyProperty.Register("ValidationTemplate", 
           typeof(ControlTemplate), 
           typeof(AutoCompleteComboBox), 
           new FrameworkPropertyMetadata(new ControlTemplate(), OnValidationTemplateChanged)); 

private static void OnValidationTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    Validation.SetErrorTemplate(d, (ControlTemplate)e.NewValue); 
} 
1

Насколько я знаю, вы не можете делать то, что вы хотите с Binding. ErrorTemplate может использоваться с StaticResource.

1

Поскольку ErrorTemplate не является связываемым, вы можете установить параметр Validation.ErrorTemplate с ресурсом, а в DependancyPropertyChange - заменить ключ ресурса обновленным значением.

<TextBox x:Name="ValueTextBox" 
      TextWrapping="NoWrap" 
      GotFocus="_ValueTextBox_GotFocus" 
      Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Canvas}}, Path=ActualWidth}" 
      Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Canvas}}, Path=ActualHeight}" 
      Validation.ErrorTemplate="{DynamicResource MyErrorTemplate}" 
      > 

и в зависимости изменения свойств:

public static readonly DependencyProperty ValidationTemplateProperty = 
     DependencyProperty.Register("ValidationTemplate" 
            , typeof(ControlTemplate) 
            , typeof(AutoCompleteComboBox) 
            , new FrameworkPropertyMetadata(new ControlTemplate(),ValidationTemplateChanged)); 

    private static void ValidationTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     AutoCompleteComboBox control = d as AutoCompleteComboBox; 
     control.Resources["MyErrorTemplate"] = e.NewValue; 
    } 
0

Вы можете определить и связать как статический ресурс:

Пример:

<Window.Resources> 
    <ControlTemplate x:Key="errorTemplate"> 
     <Border BorderBrush="Red" BorderThickness="2"> 
      <Grid> 
       <AdornedElementPlaceholder x:Name="_el" /> 
       <TextBlock Text="{Binding [0].ErrorContent}" 
          Foreground="Red" HorizontalAlignment="Right" 
          VerticalAlignment="Center" Margin="0,0,6,0"/> 
      </Grid> 
     </Border> 
    </ControlTemplate> 
</Window.Resources> 

В Элемента:

<TextBox Grid.Column="1" Margin="6" Validation.ErrorTemplate="{StaticResource errorTemplate}"> 
     <TextBox.Text> 
      <Binding Path="Name" ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged" > 
       <Binding.ValidationRules> 
        <local:MinCharsRule MinimumChars="3" /> 
       </Binding.ValidationRules> 
      </Binding> 
     </TextBox.Text> 
    </TextBox> 

Примечание: я использовал этот пример из WPF CookBook 4.5 Page 232, и он отлично работает.

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