我一直在尝试在WPF应用程序中实现一些错误验证,两天来我一直在思考如何在ListBox中正确地实现它。我使用了CommunityToolkit中的ObservableValidator和property属性,这部分看起来工作得很好。
为了给予更多的上下文,我有一个列表框,其中包含可以用几个文本框、组合框等编辑的项。我正在验证必填字段、IP地址等相当标准的内容。我的问题是,当其中一个字段有错误时,它的顶部有一个红色边框,对于另一个不相关的控件也是如此。我在这个主题上搜索了很多,我不明白为什么同一个网格中的另一个控件也在改变。
列表框的事情看起来是正常的,至少,我已经用一个非常简单的例子重现了它,我终于明白了,如果所选项目的属性之一无效,列表框就处于错误状态。可以通过在列表框上放置一个空的错误模板来停用它,所以我对它很满意。
另一方面,我完全不知道为什么项目网格中的其他控件也处于错误状态,我无法在我的简单示例中重现它。我也无法合理地共享使整个视图工作所需的所有代码,但我将尝试在下面给予最相关的部分。还请注意,我没有编写整个代码,并希望尽可能少地更改。
主视图的内容:
<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);
}
}
源项定义:
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;
}
列表框项的样式:
<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>
我已经简化了很多,通过删除面板和控件,以获得问题的核心:当名称文本框无效时,ColorIcon自定义控件也有一个红色边框,如上所示。如果所有控件都是这样,我可能会理解,但只有这个控件是这样。
在这一点上,我真的欢迎任何想法,以及关于这一切应该如何工作的解释。
编辑:我已经添加了更多的代码(应该马上共享视图模型),并试图在一些部分更清晰,我希望这会有所帮助。
1条答案
按热度按时间omjgkv6w1#
所以最后由于ListBox处理验证的方式而非常混乱,我应该早点看到真实的的问题。
就在那部分:
该控件不应该绑定到图标颜色顶部的整个SourceItem对象。当SourceItem的名称或IP地址无效时,对象本身的
HasErrors
为true,因此自定义控件也有红色边框。我删除了可能是遗留的绑定,它可以工作。另一个控件有一个作为
CommandParameter
的SourceItem,我不能那么容易地更改它,所以我在这个绑定上使用ValidatesOnNotifyDataErrors=False
,因为它似乎是本例中正确的解决方案。