使用ControlTemplate

时间:2018-06-14 11:32:10

标签: wpf data-binding

我有一个显示一些标签的列表框 然后是多个(理论上是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。

现在,当我进行验证时,由于文本框控件已更改,因此绑定已分离。 我收到以下消息:

the error message

注意:只有在同一个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

对此有任何帮助表示赞赏。

1 个答案:

答案 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 - 如果您无法提供帮助,请保留您的意见。