我有一个显示一些标签的列表框 然后是多个(理论上是n,实际上最多6个)列表框,每个列表框都显示一些值。这n个列表框中的每一个都是它自己的视图/视图模型。
现在我在列表框-ViewModel中的Value-class中更改属性“HasChanged”。我有一个从“HasChanged”到“IsSelected”的绑定。每个ViewModel中都有一个值类实例列表。
此外,我有一个侦听“IsSelected”的触发器 - 更改。 触发器的一部分是应用新的控件模板。 在该模板中,我定义了一些样式以使状态对用户可见。
现在问题是: 我正在使用“ValidatesOnExceptions”,以使用户可以看到值的无效性。 以下是value属性的代码:
public string Content
{
get
{
if (!string.IsNullOrEmpty(modifiedValue))
return modifiedValue;
return content;
}
set
{
modifiedValue = value;
HasChanged = (modifiedValue != content);
if (!string.IsNullOrEmpty(interpretAs))
Validate();
OnPropertyChanged(nameof(Content));
}
}
由于我正在设置“HasChanged”属性从而触发选择控制模板应用程序,因此控件模板会设置一个带边框的新TextBox。
现在,当我进行验证时,由于文本框控件已更改,因此绑定已分离。 我收到以下消息:
注意:只有在同一个setter-call中更改IsChanged和Validating时才会出现问题。
我注意到我可以使用大量的样式触发器而不是控件模板来解决方法。但仍有希望..当我无法使用控件模板时,我也会再次遇到焦点问题。
这是我的Grid.Resources的XAML:
<ControlTemplate x:Key="SelectedTemplate" TargetType="{x:Type ListBoxItem}">
<Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="Gray" Background="LightBlue" HorizontalAlignment="Stretch" Padding="{TemplateBinding Padding}" Margin="{TemplateBinding Margin}" >
<TextBox Text="{Binding Content, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}" Margin="0" Padding="0" BorderThickness="0" Background="Transparent" Initialized="TextBox_Initialized" ToolTip="{Binding InterpretAs}" ToolTipService.InitialShowDelay="0"/>
</Border>
</ControlTemplate>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=HasChanged}"/>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Template" Value="{StaticResource SelectedTemplate}" />
<!--<Setter Property="Border.BorderThickness" Value="1"/>
<Setter Property="Border.BorderBrush" Value="Gray"/>
<Setter Property="TextBox.Background" Value="Green"/>
<Setter Property="TextBox.HorizontalAlignment" Value="Stretch"/>-->
</MultiTrigger>
</Style.Triggers>
</Style>
<DataTemplate x:Key="ListBoxDataTemplate">
<TextBox Text="{Binding Content, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}" BorderThickness="0" Margin="0" Padding="0" Background="Transparent" ToolTip="{Binding InterpretAs}" ToolTipService.InitialShowDelay="0" />
</DataTemplate>
这是其中一个列表框的XAML:
<ScrollViewer Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="6" Scroll:ScrollSynchronizer.HorizontalScrollGroup="H0" Scroll:ScrollSynchronizer.VerticalScrollGroup="V0" VerticalScrollBarVisibility="Hidden">
<ListBox Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="6" ItemsSource="{Binding PlatformValues}" ItemTemplate="{StaticResource ListBoxDataTemplate}" PreviewMouseWheel="ListBox_PreviewMouseWheel" SelectionMode="Extended" HorizontalContentAlignment="Stretch" FocusManager.IsFocusScope="True">
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding PlatformValues.Count, FallbackValue=0, TargetNullValue=0}" Value="0">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
</ScrollViewer>
我创建了一个样本。
尝试点击文本框,然后删除最后一个字符。到现在为止还挺好。现在尝试将其设置为以“x”开头的字符串以触发验证错误,在已经更改的同一文本框上,将出现一个红色边框,表示验证错误,这就是所需的行为。
现在将一个尚未更改的TextBox直接设置为“x”,将重现所述问题。示例项目的路径:LINK REMOVED - SEE ANSWER
对此有任何帮助表示赞赏。
答案 0 :(得分:0)
答案是使用DataTemplate触发器而不是ControlTemplate 在DataTemplate中,我添加了一个默认背景透明的边框。
<DataTemplate x:Key="ListBoxDataTemplate">
<Border x:Name="ContentTextBoxBorder" BorderThickness="0" BorderBrush="Transparent" Background="Transparent" HorizontalAlignment="Stretch" Margin="-3 0">
<TextBox x:Name="ContentTextBox" Text="{Binding Content, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}" BorderThickness="0" Margin="0" Padding="0" Background="Transparent" ToolTip="{Binding InterpretAs}" ToolTipService.InitialShowDelay="0" />
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type ListBoxItem}},
Path=IsSelected}" Value="True">
<Setter TargetName="ContentTextBoxBorder" Property="Background" Value="LightGreen"/>
<Setter TargetName="ContentTextBoxBorder" Property="BorderBrush" Value="Gray"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
当项目的“IsSelected”发生变化时,我将其设置为所需的颜色。工作完美无缺。
致@Il Vic - 如果您无法提供帮助,请保留您的意见。