Soy nuevo en WPF del desarrollo, pero yo estaba pensando en cómo matar 3 pájaros de un tiro.
Ejemplo: tengo un formulario con 2 TextBox y 2 bloques de texto.
El primer ‘pájaro’ de ser capaces de «enriquecer» algunos textblock con un asterisco, si se refieren a campos requeridos:

<TextBlock Grid.Row="0" Grid.Column="0" Text="Age" customProperty="Required" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Foot Size/>

A continuación, los bloques de texto mostraría su texto de manera diferente, la primera tiene un asterisco, mientras que el que no customproperty definido no habría.

El segundo pájaro sería tener algún tipo de validación en el valor del cuadro de texto, que Si he entendido correctamente se realiza mediante el uso de un CustomValidationRule, para lo cual implementa una clase:

class AgeController: ValidationRule
{
    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        if (value == null)
            return new ValidationResult(false, "Null value");

        int temp = 1;
        Boolean noIllegalChars = int.TryParse(value.ToString(), out temp);
        if (temp >= 1)
            return new ValidationResult(true, null);
        else
            return new ValidationResult(false, "Correggi");
    }
}

Por añadir esto a la textBlox código XAML:

<TextBox.Text>
     <Binding Path="blabla" UpdateSourceTrigger="PropertyChanged"  ValidatesOnDataErrors="True">
         <Binding.ValidationRules>
              <local:AgeController ValidationStep="RawProposedValue" />
         </Binding.ValidationRules>
     </Binding>
</TextBox.Text>

Y esto funciona, PERO el proceso de validación deben ser diferentes para los obligados y no obligados campos: si es necesaria una entrada en blanco no es válida, pero si es opcional en un campo en blanco es ACEPTAR.
¿Cómo puedo lograr esto sin especificar dos diferentes ValidationRule mientras que hace referencia el textblock vinculado al cuadro de texto?

/tldr: estoy tratando de encontrar una forma de enriquecer un textblock con un atributo que añade un toque de estilo a su texto (asterisco o lo que el cliente quiere, voy a modificar la forma en que el enriquecimiento modifica el texto en un solo lugar), el cuadro de texto de validación en referencia a la enriquecido textblock sería, a continuación, se comportan de manera diferente sobre la base del valor del enriquecimiento.

Espero no estropear la explicación.

InformationsquelleAutor Massimo | 2015-10-21

4 Comentarios

  1. 9

    1. TextBlock no tiene ControlTemplate de la propiedad. Por lo que el (*) requerido no puede ser añadido a TextBlock

    Etiqueta tiene un controltemplate y puede dar el foco a un campo de entrada. Vamos a utilizar.

    Uso de Objetivo propiedad para pasar el foco al cuadro de texto al hacer Alt+F es presionado:

    <!-- Prefixing Firstname with _ allows the user to give focus
         to the textbox (Target) by pressing Alt + F-->
    
        <local:LabelWithRequiredInfo  Content="_Firstname" 
                                      IsRequired="false" 
                                      Target="{Binding ElementName=textboxFirstname,
                                      Mode=OneWay}" ... />

    La creación de una sub-clase de la Etiqueta : LabelWithRequiredInfo, por lo que un IsRequired propiedad puede ser añadido.

    (Use VS Agregar Nuevo Elemento/WPF Control Personalizado).

    2. La creación de IsRequired propiedad de dependencia para el control de modo de unión va a trabajar – la necesitamos !

    public class LabelWithRequiredInfo : Label
    {
        public bool IsRequired
        {
            get { return (bool)GetValue(IsRequiredProperty); }
            set { SetValue(IsRequiredProperty, value); }
        }
    
        //Using a DependencyProperty as the backing store for IsRequired.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsRequiredProperty =
            DependencyProperty.Register("IsRequired", typeof(bool), typeof(LabelWithRequiredInfo), new PropertyMetadata(false));
        static LabelWithRequiredInfo()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(LabelWithRequiredInfo), new FrameworkPropertyMetadata(typeof(LabelWithRequiredInfo)));
        }
    }

    3. Vamos a llenar el LabelWithRequiredInfo plantilla en Temas\Genérico.xaml

    (Pero la plantilla se diseñó por primera vez en MainWindow.xaml rigth clic en una etiqueta/plantilla de Edición/Copiar – de modo que puede visualizarse – a continuación, el contenido de la plantilla se copia en Genérico.xaml)

    <Style TargetType="{x:Type local:LabelWithRequiredInfo}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:LabelWithRequiredInfo}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                        <!-- A grid has been added to the template content to have multiple content.  -->
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="30"/>
                            </Grid.ColumnDefinitions>
                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            <!-- The Visibility  property has to be converted because it's not a bool but has a Visibility type
                                 The converter (pretty classical) can be found in the attached solution, and is declared in the resource section
                                 The binding is made on a property of the component : IsRequired
                            -->
                            <TextBlock  Text="(*)" 
                                        Visibility="{TemplateBinding IsRequired,Converter={StaticResource booleanToVisibilityConverter}}"
                                        Foreground="Red"
                                        Grid.Column="1"
                                        Margin="5 0"/>
                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
    
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    4. Declaración del convertidor en Genérico.xaml :

    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TextboxRequiredMandatoryInput">
        <local:BooleanToVisibilityConverter  x:Key="booleanToVisibilityConverter"/>

    5. Declaración de un ValidationRule teniendo en cuenta IsRequired comportamiento :

    class RequiredValidationRule : ValidationRule
    {
        public bool IsRequired { get; set; }
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            var content = value as String;
            if (content != null)
            {
                if (IsRequired && String.IsNullOrWhiteSpace(content))
                    return new ValidationResult(false, "Required content");
            }
            return ValidationResult.ValidResult;
        }
    }

    6. Y utilizar en su enlace de como lo encontró :

    <TextBox x:Name="textboxFirstname" HorizontalAlignment="Left" Height="23" Margin="236,94,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120">
        <TextBox.Text>
            <Binding Path="Firstname" UpdateSourceTrigger="PropertyChanged"  ValidatesOnDataErrors="True">
                <Binding.ValidationRules>
                    <local:RequiredValidationRule IsRequired="true" ValidationStep="RawProposedValue" />
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>

    Encontrará la solución completa aquí :

    http://1drv.ms/1igpsyb

    • ¿entiendo bien la diferencia entre lo necesario y obligatorio ? No es obligatorio aceptar como puedo mostrar ? … porque yo no entender muy bien lo que son los caracteres ilegales. Saludos
    • Lo siento @Emmanuel , por las que me refería «no se requiere». De alguna manera, en mi mente pensé obligatorio significaría otra cosa… he tenido otro trabajo que hacer así que no podía comprobar sus respuestas (lo siento @todos). Estoy triyng para validar y dar la recompensa a la persona adecuada! Mientras tanto, me gustaría dar las gracias a todos por su esfuerzo 🙂
    • En realidad a mí (y por lo que veo en diccionario de inglés), manadatory = requiere
    • Sí, pero cuando escribí la pregunta realmente pensé que era obligatorio el opuesto de lo requerido. Estoy arreglando la pregunta ahora.
    • Non c’è problema 🙂
    • A todos : acabo de hacer una edición para mostrar cómo usar el botón Destino. Gracias por la Upvotes, acabo de recibir la «Buena Respuesta de la solución» para el 10 upvotes
    • Acabo de corregir mi respuesta a quitar para quitar el IsMandatory y mantener sólo el IsRequired. Por lo que he leído de nuevo su pregunta y veo que ‘d como una solución con un ValidationRule que Valida la Edad y Necesario. Yo creo que es mejor de mantener las dos validaciones reglas separados. De todos modos, dime si es importante para usted. I ve got otra implementación de la solución va en la dirección de la facilidad de uso. Espero tener tiempo para publicar y que ‘ll apreciar.
    • He hecho una segunda respuesta de abajo que es probablemente más fácil de usar. Buena lectura

  2. 4

    Para la re-utilización y la forma en que se describe el requisito, un agregado de control puede ser necesaria. Creo que un UserControl + algunos DependencyProperty son perfectas para esto.

    Para mi UserControl, yo tendría como esta..

    <UserControl x:Class="WpfApplication1.InputFieldControl"
             x:Name="InputUserCtrl"
             ...             >
    <StackPanel x:Name="MainPanel">
        <TextBlock x:Name="Label">
            <TextBlock.Text>
                <MultiBinding StringFormat="{}{0}{1}:">
                    <Binding Path="InputLabel" ElementName="InputUserCtrl"/>
                    <Binding Path="RequiredStringSymbol" ElementName="InputUserCtrl"/>
                </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
        <TextBox x:Name="Value" Text="{Binding DataContext, ElementName=InputUserCtrl}"/>
    </StackPanel>

    Luego en su clase parcial (he añadido el número de propiedades, consulte el uso de parte):

    public partial class InputFieldControl : UserControl
    {
    //Required property
    public static readonly DependencyProperty RequiredProperty =
    DependencyProperty.Register("Required", 
    typeof(bool), typeof(InputFieldControl), 
    new PropertyMetadata(true, OnRequiredChanged));
    private static void OnRequiredChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){
    InputFieldControl ctrl = d as InputFieldControl;
    //symbol is voided
    if ((bool)e.NewValue == false)
    ctrl.RequiredStringSymbol = string.Empty;
    }
    public bool Required {
    get { return (bool)GetValue(RequiredProperty); }
    set { SetValue(RequiredProperty, value); }
    }
    //Required string symbol
    public static readonly DependencyProperty RequiredStringSymbolProperty =
    DependencyProperty.Register("RequiredStringSymbol",
    typeof(string), typeof(InputFieldControl),
    new PropertyMetadata("*"));
    public string RequiredStringSymbol{
    get { return (string)GetValue(RequiredStringSymbolProperty); }
    set { SetValue(RequiredStringSymbolProperty, value); }
    }
    //Input Label
    public static readonly DependencyProperty InputLabelProperty =
    DependencyProperty.Register("InputLabel",
    typeof(string), typeof(InputFieldControl),
    new PropertyMetadata(string.Empty));
    public string InputLabel{
    get { return (string)GetValue(InputLabelProperty); }
    set { SetValue(InputLabelProperty, value); }
    }

    Y puedo usar el control como este:

    <StackPanel>
    <customCtrl:InputFieldControl Required="True"
    RequiredStringSymbol="+" 
    InputLabel="RequiredField"/>
    <customCtrl:InputFieldControl Required="False"
    InputLabel="NormalField"/>
    <customCtrl:InputFieldControl Required="True"
    RequiredStringSymbol="*" 
    InputLabel="AnotherRequiredField">
    </customCtrl:InputFieldControl>
    </StackPanel>

    Como para la validación de parte, prefiero utilizar IDataErrorInfo. Esto puede ir de la mano con su Perspective desde ahora podemos enlazar la propiedad Requerida.

  3. 3

    Primer punto: puede definir una plantilla personalizada para sus controles, en los que habría que agregar los elementos visuales que desee ( el asterisco, etc. ) . Usted puede controlar su visibilidad mediante desencadenadores. ( usted puede hacer una pregunta por separado para obtener más detalles sobre esto)

    Segundo/Tercer: puede definir una propiedad booleana IsRequired en AgeController, y se puede establecer en TRUE/FALSE cuando la definición de la validación:

    <TextBox.Text>
    <Binding Path="blabla" UpdateSourceTrigger="PropertyChanged"  ValidatesOnDataErrors="True">
    <Binding.ValidationRules>
    <local:AgeController ValidationStep="RawProposedValue" 
    IsRequired="**True**" />
    OR: IsRequired="**False**" />
    </Binding.ValidationRules>
    </Binding>
    </TextBox.Text>

    Luego, este valor sería disponibles a la hora de la implementación de la validación:

    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
    if (IsRequired)
    {
    ...
    }
    else
    {
    ...
    }
    }
  4. 0

    Aquí está una segunda respuesta que no es exactamente Massimo pregunta.

    Yo lo hice, pensando que podría ser más fácil de usar para el diseñador XAML

    El objetivo es tener una Etiqueta (subclase realmente tener la necesaria símbolo rojo (*)) más fácil de usar.

    Se da el foco a un TexBlock gracias a la habitual de la propiedad de Destino

    <local:LabelWithRequiredInfo  Content="_Firstname" 
    Target="{Binding ElementName=textboxFirstname, Mode=OneWay}" 
    ... />  

    Y porque no es un objetivo, el LabelWithRequiredInfo puede comprobar la presencia de la RequiredValidationRule en el cuadro de texto.TextProperty.

    Así, la mayoría del tiempo no hay necesidad de un IsRequired de la propiedad.

    public LabelWithRequiredInfo()
    {
    var dpd = DependencyPropertyDescriptor.FromProperty(Label.TargetProperty, typeof(Label));
    dpd.AddValueChanged(this, SearchForRequiredValidationRule);
    }
    private void SearchForRequiredValidationRule(object sender, EventArgs e)
    {
    var textbox = Target as TextBox;
    if (textbox != null)
    {
    Binding binding = BindingOperations.GetBinding(textbox, TextBox.TextProperty);
    var requiredValidationRule = binding.ValidationRules
    .OfType<RequiredValidationRule>()
    .FirstOrDefault();
    if (requiredValidationRule != null)
    {
    //makes the required legend (red (*) for instance) to appear
    IsRequired = true;
    }
    }
    }

    Y si se requiere la leyenda debe ser proporcionada en una casilla de verificación o un combobox o lo que sea, todavía hay un IsRequired de la propiedad en el LabelWithRequiredInfo

    <local:LabelWithRequiredInfo  Content="_I agree with the terms of contract" 
    Target="{Binding ElementName=checkboxIAgree}"
    IsRequired='"true"                                  
    ... />

    Y todavía es posible agregar otras reglas de validación en el cuadro de texto (o cualquier control) para comprobar si un número, regex, …

    Y último bono, establecer el RequiredLegend como una propiedad de dependencia en la LabelWithRequiredInfo:

    public Object RequiredLegend
    {
    get { return (Object)GetValue(RequiredLegendProperty); }
    set { SetValue(RequiredLegendProperty, value); }
    }
    //Using a DependencyProperty as the backing store for RequiredLegend.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty RequiredLegendProperty =
    DependencyProperty.Register("RequiredLegend", typeof(Object), typeof(LabelWithRequiredInfo), new PropertyMetadata(null));

    De modo que la plantilla de LabelWithRequiredInfo puede utilizar para mostrar texto :

    <local:LabelWithRequiredInfo RequiredLegend="(*)" ... />

    O algo más XAML-ish :

    <local:LabelWithRequiredInfo ... >
    <local:LabelWithRequiredInfo.RequiredLegend>
    <TextBlock Text="(*)" Foreground="Red" />
    </local:LabelWithRequiredInfo.RequiredLegend>

    Sólo hay que cambiar la plantilla de control en temas\Genérico.xaml.

    Ahora utiliza un ContentControl para mostrar texto o un control :

    <Style TargetType="{x:Type local:LabelWithRequiredInfo}">
    <Setter Property="Template">
    <Setter.Value>
    <ControlTemplate TargetType="{x:Type local:LabelWithRequiredInfo}">
    <Border ...>
    <Grid>
    <Grid.ColumnDefinitions ... />
    <ContentPresenter ... />
    **<ContentControl Content="{TemplateBinding RequiredLegend}" Visibility="{TemplateBinding IsRequired,Converter={StaticResource booleanToVisibilityConverter}}" Grid.Column="1" /> **
    </Grid>

    Aquí está el enlace a la solución completa de trabajo : http://1drv.ms/1MxltVZ

    Mejor codificación

Dejar respuesta

Please enter your comment!
Please enter your name here