我有一个在表单中使用的自定义控件,此控件组合了标签和文本框。当表单处于只读模式时,控件将更改为显示标签而不是文本框。 为此,我为我的控件定义了一个内容模板,如下所示:
<Style TargetType="{x:Type Controls:FormFieldControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<AdornerDecorator Grid.Column="1"
Visibility="{Binding RelativeSource={RelativeSource AncestorType=Controls:FormFieldControl},
Path=IsReadOnly,
Converter={StaticResource BooleanToInverseVisibilityConverter},
Mode=OneWay}">
<ContentPresenter Name="ContentPresenter" />
</AdornerDecorator>
<AdornerDecorator Grid.Column="1"
Visibility="{Binding RelativeSource={RelativeSource AncestorType=FormFieldControl},
Path=IsReadOnly, Converter={StaticResource BooleanToVisibilityConverter},
Mode=OneWay}">
<ContentPresenter Name="ReadOnlyContentPresenter" />
</AdornerDecorator>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
ReadOnlyContentPresenter
的内容是一个已应用以下风格的标签:
<Style x:Key="ReadOnlyFormFieldControl" TargetType="{x:Type Label}">
<Setter Property="Width" Value="400" />
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Controls:FormFieldControl},
Path=ReadOnlyWidth,
Converter={StaticResource IsSetConverter}}"
Value="True">
<Setter Property="Width"
Value="{Binding RelativeSource={RelativeSource AncestorType=Controls:FormFieldControl}, Path=ReadOnlyWidth}" />
</DataTrigger>
</Style.Triggers>
</Style>
这适用于大约80个控件,但是当我向表单添加更多控件时,标签样式中的绑定无法找到源(错误4):
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='MyProject.Controls.FormFieldControl', AncestorLevel='1''. BindingExpression:Path=ReadOnlyWidth; DataItem=null; target element is 'Label' (Name=''); target property is 'ReadOnlyWidth' (type 'Double?')
应用于控件的可编辑部分的样式也会发生同样的情况。我认为这个问题与正在处理的控件数量有关,如果我移动控制代码没有。 81(失败)在控制号之上。 80(工作),控制中的绑定没有。 81现在有效,但对照没有。 80失败了。我为几个控件做了这个,行为是一致的。
我仍然不清楚AdornerDecorator
如何正常工作,而在调查中我发现这个question提到了一个问题,即在一个adornerlayer中有超过144个装饰者,所以我删除了AdornerDecorator
在我的代码中只发现正在发生的绑定问题控制没有。 81及以上现在发生在我FormFieldControl
的所有人身上。
最后,我决定在我的控件模板中尝试ContentControl
而不是ContentPresenter
。这适用于表单中的所有控件。我知道ContentPresenter
是ContentControl
的轻量级形式,并且它比ContentControl
更适合在内容模板中使用。但是,我不太明白为什么绑定在使用ContentPresenter
时失败并且在使用ContentControl
时工作。
我也觉得很奇怪,只有一组有限的控件可以使用,而且当不使用AdornerDecorator时,它们都不会找到绑定源。
有没有人遇到类似的东西?我ContentPresenter
有什么问题吗?或者,如果这是预期的行为,有人可以帮我理解发生了什么吗?
任何想法都表示赞赏。
答案 0 :(得分:0)
从您的问题不清楚标签是否只显示文本框中的内容,或者是否必须显示自定义标签,但如果是前者,那么我认为您应该使用已提及的IsReadOnly
属性。
您可以定义一个自定义ControlTemplate
,当TextBox
被读取时,它会隐藏Label
的背景和边框,使其看起来好像只是<StackPanel>
<StackPanel.Resources>
<Style x:Key="{x:Type TextBox}"
TargetType="{x:Type TextBoxBase}">
<Setter Property="SnapsToDevicePixels"
Value="True" />
<Setter Property="OverridesDefaultStyle"
Value="True" />
<Setter Property="KeyboardNavigation.TabNavigation"
Value="None" />
<Setter Property="FocusVisualStyle"
Value="{x:Null}" />
<Setter Property="MinWidth"
Value="120" />
<Setter Property="MinHeight"
Value="20" />
<Setter Property="AllowDrop"
Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBoxBase}">
<Border Name="Border"
CornerRadius="2"
Padding="2"
Background="AliceBlue"
BorderBrush="Black"
BorderThickness="1">
<ScrollViewer Margin="0"
x:Name="PART_ContentHost" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsReadOnly"
Value="True">
<Setter TargetName="Border"
Property="Background"
Value="Transparent" />
<Setter TargetName="Border"
Property="BorderBrush"
Value="Transparent" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</StackPanel.Resources>
<TextBox Margin="50,25"
Name="tb" />
<Button Content="Switch modes"
Margin="50,25"
Click="Button_Click" />
</StackPanel>
。
试试这个简单的例子:
private void Button_Click(object sender, RoutedEventArgs e)
{
tb.IsReadOnly = !tb.IsReadOnly;
}
您需要以下按钮单击处理程序才能切换只读模式:
TextBox
以下是TextBox
可编辑时的结果:
这就是{{1}}在只读时的样子。
答案 1 :(得分:0)
我认为原因可能就是这个:
var contentPresenter = new ContentPresenter { Content = new Button() };
var contentControl = new ContentControl { Content = new Button() };
if ((contentPresenter.Content as FrameworkElement).Parent == null)
Debug.WriteLine("ContentPresenter won't let you get ancestors");
if ((contentControl.Content as FrameworkElement).Parent != null)
Debug.WriteLine("ContentControl will let you get ancestors");
显示两行,这意味着contentPresenter是罕见的FrameworkElement之一,没有正确设置&#34; Parent&#34;属性。