提问人:blazcowicz 提问时间:3/15/2023 最后编辑:blazcowicz 更新时间:3/16/2023 访问量:49
为什么验证错误在 ListBox 和 ListBoxItem 中无法按预期工作?
Why are validation errors not working as expected inside ListBox and ListBoxItem?
问:
我一直在尝试在 WPF 应用程序中实现一些错误验证,并且我已经为如何在 ListBox 中正确执行此操作而绞尽脑汁了两天。我正在使用 ObservableValidator 和 CommunityToolkit 中的属性,该部分似乎工作正常。
为了提供更多上下文,我有一个 ListBox,其中包含每个项目都可以使用多个 TextBox、ComboBox 等进行编辑。我正在验证诸如必填字段,IP地址之类的东西,相当标准的东西。我的问题是,当其中一个字段出现错误时,除了它有一个红色边框之外,另一个不相关的控件也会出现同样的情况。我已经在这个主题上搜索了很多,我不明白为什么同一网格中的另一个控件也在变化。
至少 ListBox 的事情似乎是正常的,我用一个非常简单的示例重现了它,我终于明白,如果所选项的某个属性无效,则 ListBox 处于错误状态。可以通过在 ListBox 上放置一个空的错误模板来停用它,所以我对它很好。
另一方面,我完全不知道为什么项目网格内的其他一些控件也处于错误状态,并且我无法在我的简单示例中重现它。我也无法合理地共享使整个视图工作所需的所有代码,但我会尝试在下面提供最相关的部分。另请注意,我没有编写整个代码,并希望更改尽可能少的数量。
主视图内容:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0" Background="Transparent" Margin="10"
ItemsSource="{Binding Sources}"
SelectedItem="{Binding SelectedSource}"
ItemContainerStyle="{DynamicResource SourceListBoxItem}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<Grid>
对应的视图模型:
public partial class SourcesViewModel : ObservableObject, IMenuItemViewModel
{
private readonly IDialogService dialogService;
[ObservableProperty]
private SourceItem selectedSource = new();
[ObservableProperty]
private ObservableCollection<SourceItem> sources;
public SourcesViewModel(IDialogService dialogServiceParam)
{
dialogService = dialogServiceParam;
}
[RelayCommand]
private void ShowColorIconDialog()
{
ColorIcon colorIcon = new(SelectedSource.Icon, SelectedSource.Color);
dialogService.ShowDialog<ColorIconSelectionViewModel>(colorIcon);
}
}
SourceItem 定义:
public partial class SourceItem : ObservableValidator, ICloneable
{
public SourceItem() { }
[ObservableProperty]
private int id;
[ObservableProperty]
[NotifyDataErrorInfo]
[Required(ErrorMessage = "Name is required")]
private string name;
[ObservableProperty]
private string color;
[ObservableProperty]
[NotifyDataErrorInfo]
[Required(ErrorMessage = "Icon is required")]
private string icon;
}
ListBox 项的样式:
<Style x:Key="SourceListBoxItem" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<customControls:CustomExpander x:Name="Expander"
Width="650"
Template="{DynamicResource ExpanderTemplate}"
IsExpanded="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}}"
OverridesDefaultStyle="True"
TitlePart1="{lex:Loc Label_Sources_SourceHeader}"
TitlePart2="{Binding Id, StringFormat={}{0} :}"
TitlePart3="{Binding Name, ValidatesOnNotifyDataErrors=False}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="10,2">
</customControls:CustomExpander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
扩展器内容的数据模板:
<DataTemplate x:Key="ExpanderContentTemplate" xmlns:enum="clr-namespace:Medinbox.RoomManager.Models.Enums">
<Grid Background="{DynamicResource WhiteBrush}">
<StackPanel Orientation="Vertical" Margin="10,5">
<TextBlock Text="{lex:Loc Label_Sources_SourceName}"/>
<TextBox Text="{Binding DataContext.Name, RelativeSource={RelativeSource AncestorType=ListBoxItem}}">
</TextBox>
</StackPanel>
<StackPanel>
<userControls:SourceIconColorButton BackgroundColor="{Binding DataContext.Color, RelativeSource={RelativeSource AncestorType=ListBoxItem }}"
IconName="{Binding DataContext.Icon, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType= ListBoxItem}}"
Command ="{Binding DataContext.ShowColorIconDialogCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
</StackPanel>
</Grid>
</DataTemplate>
我通过删除面板和控件来简化它,以解决问题的核心:当名称 TextBox 无效时,ColorIcon 自定义控件也有一个红色边框,如上所示。如果所有控件都是这种情况,我可能会理解,但这只是这个。
在这一点上,我非常欢迎任何想法,以及关于这一切应该如何工作的解释。
编辑:我已经添加了更多代码(应该立即共享视图模型)并试图在某些部分上更清晰,我希望它有所帮助。
答:
所以最后,由于 ListBox 如何处理验证,它非常令人困惑,我应该更早地看到真正的问题。
正是在那部分:
<userControls:SourceIconColorButton BackgroundColor="{Binding DataContext.Color, RelativeSource={RelativeSource AncestorType=ListBoxItem }}"
IconName="{Binding DataContext.Icon, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType= ListBoxItem}}"
Command ="{Binding DataContext.ShowColorIconDialogCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
该控件不应绑定到整个 SourceItem 对象的颜色图标顶部。当 SourceItem 的名称或 IP 地址无效时,对象本身为 true,因此自定义控件也具有红色边框。我删除了可能是剩余的绑定,它有效。HasErrors
另一个控件有一个 SourceItem 作为 a,我无法轻易更改它,所以我使用了这个绑定,因为在这种情况下它似乎是正确的解决方案。CommandParameter
ValidatesOnNotifyDataErrors=False
评论