我有一个在表单中使用的自定义控件,这个控件结合了标签和文本框。当窗体处于只读模式时,控件将更改为显示标签而不是文本框。为此,我为控件定义了一个内容模板,如下所示:
<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提到了装饰层中有144个以上装饰器的问题,所以我删除了代码中的AdornerDecorator,结果却发现发生在第81号或更高版本控件上的绑定问题现在也发生在我所有的FormFieldControl上。
最后,我决定尝试在我的控件模板中使用ContentControl的而不是ContentPresenter的。这对表单中的所有控件都很有效。我知道ContentPresenter是ContentControl的轻量级形式,它比ContentControl更适合在内容模板中使用。然而,我不太明白为什么在使用ContentPresenter时绑定会失败,而在使用ContentControl时会起作用。
我还发现奇怪的是,只有有限的一组控件可以工作,并且当不使用AdornerDecorator时,它们都不会找到绑定源。
有没有人遇到过类似的事情?我是不是对ContentPresenter做错了什么?或者,如果这是意料之中的行为,有人能帮我理解一下发生了什么吗?
任何想法都是值得感谢的。
发布于 2012-11-28 01:01:41
从你的问题中不清楚标签是只显示文本框中的内容,还是必须显示自定义标签,但如果是前者,那么我认为您应该像前面提到的那样使用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在只读时的样子。

发布于 2014-10-21 18:24:43
我认为原因可能是这样的:
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是少数未正确设置"Parent“属性的FrameworkElement之一。
https://stackoverflow.com/questions/13001939
复制相似问题