2012-10-21 141 views
3

我有一個在窗體中使用的自定義控件,此控件組合了一個標籤和一個文本框。當表單處於只讀模式時,控件將更改爲顯示標籤而不是文本框。 要做到這一點,我已經定義了我的控制內容的模板,內容如下:WPF - 無法將ContentPresenter中控件的屬性綁定到父控件

<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

想一想,當你的表單是隻讀的,爲什麼不把你的文本框設置爲只讀呢? (IsReadOnly = true) – Surfbutler

+0

這不是真的取決於我,而是要顯示標籤。 – dzavala

回答

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可編輯:

enter image description here

And t他是TextBox只讀時的樣子。

enter image description here

+0

感謝您的回答,這是一個簡單的解決方法。但是,如果我使用ContentControl,我的控件工作得很好,所以問題更多地與我使用ContentPresenter時控件的行爲不同有關。如果在我的問題中沒有明確表示道歉。 – dzavala

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的不正確設置了「家長」屬性之一。

相關問題