Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#wpf-如何在自定义控件中将文本框错误传递给父级_C#_Wpf - Fatal编程技术网

C#wpf-如何在自定义控件中将文本框错误传递给父级

C#wpf-如何在自定义控件中将文本框错误传递给父级,c#,wpf,C#,Wpf,我尝试创建一个具有多级验证的文本框,因此如果有一些字段应该填写但不是必需的,请通知用户。我创建了一个控件,效果非常好,我只有一个问题。我想在其他用户控件中使用此新文本框。我有一个保存按钮,我想在这个文本框没有验证错误时启用这个按钮,但是验证错误似乎在我的自定义文本框控件中,所以这个按钮总是启用的。以下是控制xaml代码: MultiLevelValidationTextBox.xaml <Style x:Key="MultiLevelValidationTextBoxStyle" Tar

我尝试创建一个具有多级验证的文本框,因此如果有一些字段应该填写但不是必需的,请通知用户。我创建了一个控件,效果非常好,我只有一个问题。我想在其他用户控件中使用此新文本框。我有一个保存按钮,我想在这个文本框没有验证错误时启用这个按钮,但是验证错误似乎在我的自定义文本框控件中,所以这个按钮总是启用的。以下是控制xaml代码:

MultiLevelValidationTextBox.xaml

<Style x:Key="MultiLevelValidationTextBoxStyle"  TargetType="local:MultiLevelValidationTextBoxControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:MultiLevelValidationTextBoxControl">
                <Grid>
                    <Grid.Resources>
                        <local:IsNullConverter x:Key="IsNullConverter" />
                    </Grid.Resources>
                    <TextBox
                        x:Name="PART_TextBox"
                        Text="{Binding Path=BindingText, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}">
                        <TextBox.Style>
                            <Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
                                <Style.Triggers>
                                    <MultiDataTrigger>
                                        <MultiDataTrigger.Conditions>
                                            <Condition Binding="{Binding Path=Recommended, RelativeSource={RelativeSource Mode=TemplatedParent}}" Value="True"/>
                                            <Condition Binding="{Binding Path=BindingText, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource IsNullConverter}}" Value="True"/>
                                        </MultiDataTrigger.Conditions>
                                        <Setter Property="BorderBrush" Value="#fcba03" />
                                    </MultiDataTrigger>
                                    <DataTrigger Binding="{Binding Path=Required, RelativeSource={RelativeSource Mode=TemplatedParent}}" Value="True">
                                        <Setter Property="Text">
                                            <Setter.Value>
                                                <Binding Path="BindingText" RelativeSource="{RelativeSource Mode=TemplatedParent}" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay">
                                                    <Binding.ValidationRules>
                                                        <local:TextBoxTextValidation ValidatesOnTargetUpdated="True"/>
                                                    </Binding.ValidationRules>
                                                </Binding>
                                            </Setter.Value>
                                        </Setter>
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </TextBox.Style>
                    </TextBox>
                    <Polygon x:Name="PART_Polygon" Points="0,0 5,0 0,5 0,0" Margin="0,3,2,0" HorizontalAlignment="Right" FlowDirection="RightToLeft" ToolTip="A mező kitöltése ajánlott!">
                        <Polygon.Style>
                            <Style TargetType="Polygon">
                                <Style.Triggers>
                                    <MultiDataTrigger>
                                        <MultiDataTrigger.Conditions>
                                            <Condition Binding="{Binding Path=Recommended, RelativeSource={RelativeSource Mode=TemplatedParent}}" Value="True"/>
                                            <Condition Binding="{Binding Path=BindingText, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource IsNullConverter}}" Value="True"/>
                                        </MultiDataTrigger.Conditions>
                                        <Setter Property="Fill" Value="#fcba03" />
                                    </MultiDataTrigger>
                                    <MultiDataTrigger>
                                        <MultiDataTrigger.Conditions>
                                            <Condition Binding="{Binding Path=Recommended, RelativeSource={RelativeSource Mode=TemplatedParent}}" Value="True"/>
                                            <Condition Binding="{Binding Path=BindingText, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource IsNullConverter}}" Value="False"/>
                                        </MultiDataTrigger.Conditions>
                                        <Setter Property="Fill" Value="Transparent" />
                                    </MultiDataTrigger>
                                    <MultiDataTrigger>
                                        <MultiDataTrigger.Conditions>
                                            <Condition Binding="{Binding Path=Recommended, RelativeSource={RelativeSource Mode=TemplatedParent}}" Value="False"/>
                                        </MultiDataTrigger.Conditions>
                                        <Setter Property="Fill" Value="Transparent" />
                                    </MultiDataTrigger>
                                </Style.Triggers>
                            </Style>
                        </Polygon.Style>
                    </Polygon>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
我还有一个窗口,我想在这里使用它,如果需要texbox,有一个按钮应该被禁用:

<Button
                         Grid.Row="1"
            Grid.Column="6"
            Margin="10,0,0,0" 
            MinWidth="80" 
            Height="30">

那么,有没有办法将验证错误传递给父级?一切正常,只是这部分失灵

                    <Button.Style>
                        <Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
                            <Setter Property="IsEnabled" Value="False"/>
                            <Style.Triggers>
                                <MultiDataTrigger>
                                    <MultiDataTrigger.Conditions>
                                        <Condition Binding="{Binding ElementName=CustomTextBoxName, Path=(Validation.HasError), UpdateSourceTrigger=PropertyChanged}" Value="False" />
                                    </MultiDataTrigger.Conditions>
                                    <Setter Property="IsEnabled" Value="True"/>
                                </MultiDataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Button.Style>

                    Save
                </Button>

拯救

首先,您的代码太复杂,因此很难理解。您不必在
文本框
控制模板
内放置
文本框
。那太荒谬了。如果您不知道控件的树是如何设计的,请始终查看并查找所需的控件。
在你的情况下,这是最重要的。在这里,您可以了解到
文本框
的内容托管在
滚动查看器
中,该查看器实际上是一个提供内容滚动的
内容控件

这是
文本框
的精简
控制模板
(请访问上一链接查看完整代码):

验证失败时显示的
控制模板

<ControlTemplate x:Key="ValidationErrorTemplate">
  <DockPanel>
    <TextBlock Text="!"
               Foreground="#FCBA03" 
               FontSize="20" />
    <Border BorderThickness="2" 
            BorderBrush="#FCBA03"
            VerticalAlignment="Top">
      <AdornedElementPlaceholder/>
    </Border>
  </DockPanel>
</ControlTemplate>
要将此
TextBox
验证错误绑定到其他控件(如果使用绑定验证),只需执行以下操作:

<StackPanel>

  <!-- Button will be disabled when the TextBox has validation errors -->
  <Button Content="Press Me" Height="40">
    <Button.Style>
      <Style TargetType="Button">
        <Style.Triggers>
          <DataTrigger Binding="{Binding ElementName=ValidatedTextBox, Path=(Validation.HasError)}" 
                       Value="True">
            <Setter Property="IsEnabled" Value="False" />
          </DataTrigger>
        </Style.Triggers>
      </Style>
    </Button.Style>
  </Button>
  <TextBox x:Name="ValidatedTextBox" 
           Validation.ErrorTemplate="{StaticResource ValidationErrorTemplate}"
           Style="{StaticResource TextBoxStyle}">
      <TextBox.Text>
        <Binding Path="BindingText" 
                 RelativeSource="{RelativeSource TemplatedParent}"
                 UpdateSourceTrigger="PropertyChanged">
          <Binding.ValidationRules>
            <local:TextBoxTextValidation ValidatesOnTargetUpdated="True"/>
          </Binding.ValidationRules>
        </Binding>
      </TextBox.Text>
    </TextBox>
</StackPanel>

这是一个有效的例子。您只需根据一些
Required
属性添加条件验证即可对其进行扩展。只需将触发器添加到
TextBoxStyle
。无需从
TextBox
派生并创建自定义控件


评论
我强烈建议通过实现()在视图模型中实现数据验证。这增加了更多的灵活性和更简单的UI设计,因为绑定路径将被简化,UI膨胀将被删除。它还加强了封装(改进了设计),并支持对完整的验证逻辑进行单元测试。

什么样的验证?乍一看你做错了什么。为什么您的文本框样式在其
ControlTemplate
中有一个
TextBox
?你想做什么?@BionicCode我有一个表单,有很多字段、文本框、组合框等,我想标记必填字段和推荐字段。必填字段很容易,因为我可以使用验证。但是有些字段只是推荐的,但是用户不必填写。还有一个管理员,他可以设置哪些字段是必需的,哪些是推荐的。因此,我无法创建一些具有必需样式的字段,以及一些具有推荐样式的字段,因为管理员可以动态更改该字段是必需的、推荐的还是两者都没有。您如何知道哪些字段被管理员标记为必需的?是的,一定要进行VH ViewModel验证。更容易测试,更容易绑定,更容易禁用无效data@KrzysztofSkowronek是的,你说得对。我怎么会忘记提到遗嘱呢?非常感谢。
<TextBox Validation.ErrorTemplate="{StaticResource ValidationErrorTemplate}"
         Style="{StaticResource TextBoxStyle}">
  <TextBox.Text>
    <Binding Path="BindingText" 
             RelativeSource="{RelativeSource TemplatedParent}"
             UpdateSourceTrigger="PropertyChanged">
      <Binding.ValidationRules>
        <local:TextBoxTextValidation ValidatesOnTargetUpdated="True"/>
      </Binding.ValidationRules>
    </Binding>
  </TextBox.Text>
</TextBox>
<ControlTemplate x:Key="ValidationErrorTemplate">
  <DockPanel>
    <TextBlock Text="!"
               Foreground="#FCBA03" 
               FontSize="20" />
    <Border BorderThickness="2" 
            BorderBrush="#FCBA03"
            VerticalAlignment="Top">
      <AdornedElementPlaceholder/>
    </Border>
  </DockPanel>
</ControlTemplate>
<Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}">
  <Style.Triggers>
    <Trigger Property="Validation.HasError" Value="true">
      <Setter Property="ToolTip"
        Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                        Path=(Validation.Errors)/ErrorContent}"/>
    </Trigger>
  </Style.Triggers>
</Style>
<StackPanel>

  <!-- Button will be disabled when the TextBox has validation errors -->
  <Button Content="Press Me" Height="40">
    <Button.Style>
      <Style TargetType="Button">
        <Style.Triggers>
          <DataTrigger Binding="{Binding ElementName=ValidatedTextBox, Path=(Validation.HasError)}" 
                       Value="True">
            <Setter Property="IsEnabled" Value="False" />
          </DataTrigger>
        </Style.Triggers>
      </Style>
    </Button.Style>
  </Button>
  <TextBox x:Name="ValidatedTextBox" 
           Validation.ErrorTemplate="{StaticResource ValidationErrorTemplate}"
           Style="{StaticResource TextBoxStyle}">
      <TextBox.Text>
        <Binding Path="BindingText" 
                 RelativeSource="{RelativeSource TemplatedParent}"
                 UpdateSourceTrigger="PropertyChanged">
          <Binding.ValidationRules>
            <local:TextBoxTextValidation ValidatesOnTargetUpdated="True"/>
          </Binding.ValidationRules>
        </Binding>
      </TextBox.Text>
    </TextBox>
</StackPanel>