C# WPF验证取决于必填/非必填字段

C# WPF验证取决于必填/非必填字段,c#,wpf,validation,xaml,C#,Wpf,Validation,Xaml,我是WPF开发的新手,但我正在考虑如何一石三鸟。 示例:我有一个包含2个文本框和2个文本块的表单。 第一个“bird”是,如果某些文本块引用必填字段,则可以使用星号“充实”它们: 第一点:您可以为控件定义自定义模板,在其中添加所需的可视元素(星号等)。可以使用触发器控制其可见性。(关于这方面的更多细节,您可以单独提问) Second/Third:您可以在AgeController上定义布尔属性IsRequired,并在定义验证时将其设置为TRUE/FALSE: <TextBox.Text

我是WPF开发的新手,但我正在考虑如何一石三鸟。 示例:我有一个包含2个文本框和2个文本块的表单。 第一个“bird”是,如果某些文本块引用必填字段,则可以使用星号“充实”它们:



第一点:您可以为控件定义自定义模板,在其中添加所需的可视元素(星号等)。可以使用触发器控制其可见性。(关于这方面的更多细节,您可以单独提问)

Second/Third:您可以在
AgeController
上定义布尔属性
IsRequired
,并在定义验证时将其设置为TRUE/FALSE:

<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>

1。TextBlock没有ControlTemplate属性。因此,所需的(*)不能添加到文本块中

<local:LabelWithRequiredInfo  Content="_Firstname" 
                              Target="{Binding ElementName=textboxFirstname, Mode=OneWay}" 
                              ... />  
Label有一个controltemplate,可以为输入字段提供焦点。让我们使用它

按下Alt+F时,使用Target属性将焦点传递给文本框:

<!-- 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}" ... />
3。让我们用Themes\Generic.xaml中的RequiredInfo模板填充Label

<local:LabelWithRequiredInfo  Content="_Firstname" 
                              Target="{Binding ElementName=textboxFirstname, Mode=OneWay}" 
                              ... />  
(但是模板首先是在MainWindow.xaml right中设计的,单击标签/编辑模板/复制-因此可以可视化-然后模板内容在Generic.xaml中复制)

6。并在您找到的绑定中使用它:

<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>

您将在此处找到完整的解决方案:


对于可重用性和您描述需求的方式,可能需要一个聚合控件。我认为UserControl+一些DependencyProperty是一个完美的选择

对于我的UserControl,我希望

<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>
我可以像这样使用控件:

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


至于验证部分,我宁愿使用IDataErrorInfo。这可以与您的ViewModel一起使用,因为我们现在可以绑定所需的属性。

这里是第二个答案,它并不完全是Massimo的问题

我这样做了,因为我认为对于XAML设计器来说,它可能更容易使用

目标是使标签(子类实际上具有所需的红色符号(*))更易于使用

由于通常的目标属性

<local:LabelWithRequiredInfo  Content="_Firstname" 
                              Target="{Binding ElementName=textboxFirstname, Mode=OneWay}" 
                              ... />  
因此,LabelWithRequiredInfo的模板可以使用它来显示一些文本:

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

或者更像XAML的东西:

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

只需在themes\Generic.xaml中更改控件模板

它现在使用ContentControl显示文本或控件:

<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>

** **
以下是完整工作解决方案的链接:


最佳编码

@Massimo,我是否很好地理解了必选和必选之间的区别?如我所示,强制可以吗。。。因为我不太清楚什么是非法字符。Regardsorry@Emmanuel,我指的是“不需要”。不知怎的,在我的脑海里,我认为强制性意味着另一件事。。。我还有其他工作要做,所以我无法查看您的回复(抱歉@all)。我是崔恩来确认并把赏金给合适的人!同时,我要感谢大家的努力:)事实上,对我来说(从我在英语词典中看到的),manadatory=required是的,但当我写这个问题时,我真的认为强制性与强制性相反。我现在正在解决这个问题。对每个人来说:我只是做了一个编辑来展示如何使用目标按钮。谢谢你的投票,我刚刚得到了10票的“好答案解决方案”
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); }
    }
<StackPanel>
    <customCtrl:InputFieldControl Required="True"
                                  RequiredStringSymbol="+" 
                                  InputLabel="RequiredField"/>
    <customCtrl:InputFieldControl Required="False"
                                  InputLabel="NormalField"/>
    <customCtrl:InputFieldControl Required="True"
                                  RequiredStringSymbol="*" 
                                  InputLabel="AnotherRequiredField">
    </customCtrl:InputFieldControl>
</StackPanel>
<local:LabelWithRequiredInfo  Content="_Firstname" 
                              Target="{Binding ElementName=textboxFirstname, Mode=OneWay}" 
                              ... />  
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;
        }
    }
}
<local:LabelWithRequiredInfo  Content="_I agree with the terms of contract" 
                              Target="{Binding ElementName=checkboxIAgree}"
                              IsRequired='"true"                                  
                              ... />
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));
<local:LabelWithRequiredInfo RequiredLegend="(*)" ... />
<local:LabelWithRequiredInfo ... >
    <local:LabelWithRequiredInfo.RequiredLegend>
        <TextBlock Text="(*)" Foreground="Red" />
    </local:LabelWithRequiredInfo.RequiredLegend>
<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>