2011-03-24 58 views
1

我非常新的WPF(使用了它3周)的價值,所以我可能會丟失一些愚蠢或不理解我在做什麼!WPF在用戶控件設置控件模板的內容對DependencyProperty

我試圖創建一個能夠覆蓋或者整個應用程序或電流控制是在模式類型彈出窗口。我想這種控制是半透明,因此用戶仍然可以看到後面的內容,但不能用它。然後,他們將能夠在繼續之前完成模態窗口中的任何事情。

我不希望有在不同的地方重複代碼,所以我的目標是有一個通用的控制,我可以在我的XAML中使用,只需要添加每次我需要的內容。即褪色,透明度,背景顏色額外的在一個地方的所有處理,我只需要添加特定功能的它該實例。

到目前爲止,我已經創建了一個名爲jonblind用戶控件:

<UserControl x:Class="ShapInteractiveClient.View.SampleTests.jonblind" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     mc:Ignorable="d" 
     d:DesignHeight="300" d:DesignWidth="300"> 


<Grid x:Name="blindGrid" Grid.RowSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
     Opacity="0.82"> 
    <Grid.Background> 
     <LinearGradientBrush EndPoint="0,1" StartPoint="0,0" MappingMode="RelativeToBoundingBox"> 
      <GradientStop Color="#FFA8CBFE" Offset="1"/> 
      <GradientStop Color="Red"/> 
      <GradientStop Color="#FFE1EDFE" Offset="0.147"/> 
     </LinearGradientBrush> 
    </Grid.Background> 

    <ContentControl x:Name="contentTemplateArea" /> 

</Grid> 

</UserControl> 

我有一個代碼背後的控制如下:

public partial class jonblind : UserControl 
{ 
    public jonblind() 
    { 
     InitializeComponent(); 
     SetVisibility(this); 
    } 

    [Category("jonblind")] 
    public bool IsContentVisible 
    { 
     get { return (bool)GetValue(IsContentVisibleProperty); } 
     set { SetValue(IsContentVisibleProperty, value); } 
    } 

    public static readonly DependencyProperty IsContentVisibleProperty = DependencyProperty.Register("IsContentVisible", typeof(bool), typeof(jonblind), 
     new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIsOverlayContentVisibleChanged))); 

    private static void OnIsOverlayContentVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     jonblind blind = d as jonblind; 
     if(blind != null) 
      SetVisibility(blind); 
    } 

    private static void SetVisibility(jonblind blind) 
    { 
     blind.blindGrid.Visibility = blind.IsContentVisible ? Visibility.Visible : Visibility.Hidden; 
    } 



    [Category("jonblind")] 
    public ContentControl ContentAreaControl 
    { 
     get { return (ContentControl)GetValue(ContentAreaControlProperty); } 
     set { SetValue(ContentAreaControlProperty, value); } 
    } 

    public static readonly DependencyProperty ContentAreaControlProperty = DependencyProperty.Register("ContentAreaControl", typeof(ContentControl), typeof(jonblind), 
     new FrameworkPropertyMetadata(new PropertyChangedCallback(OnContentAreaControlChanged))); 

    private static void OnContentAreaControlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     jonblind blind = d as jonblind; 
     if (blind != null && e.NewValue != null && e.NewValue is ContentControl) 
     { 
      blind.contentTemplateArea = e.NewValue as ContentControl; 
     } 
    } 
} 

我可以如下把它添加到其他用戶控件:

<UserControl.Resources> 
<ContentControl x:Key="testcontrol"> 
     <StackPanel> 
      <TextBox VerticalAlignment="Center" HorizontalAlignment="Center" Text="Loading!!!" /> 
      <Button Content="hide me!" Command="{Binding Path=alternateblind}" /> 
     </StackPanel> 
    </ContentControl> 
</UserControl.Resources> 

<SampleTests:jonblind IsContentVisible="{Binding Path=ShowBlind}" ContentAreaControl="{StaticResource testcontrol}" /> 

如果我把一個斷點放在「OnContentAreaControlChanged」上,我可以看到新內容被傳入,但不會在運行時顯示。

我不知道如果我要對此都錯了,如果它甚至有可能,如果它只是需要tweeking。任何和所有這方面的意見和處理這種情況將不勝感激。

回答

1

這是一種常見的圖案n的WPF所使用的大量的內置的自ContentControl導出對照(1片子內容的),HeaderedContentControl(2個子內容的),或ItemsControl的(正的兒童的集合)。一般來說,內容屬性(在運行時將被替換爲佔位符的內容)應該是類型對象。您也可以擺脫更改處理程序,並在此情況下依賴數據綁定。

[Category("jonblind")] 
public object ContentAreaControl 
{ 
    get { return GetValue(ContentAreaControlProperty); } 
    set { SetValue(ContentAreaControlProperty, value); } 
} 

public static readonly DependencyProperty ContentAreaControlProperty = 
    DependencyProperty.Register("ContentAreaControl", typeof(object), typeof(jonblind), 
    new FrameworkPropertyMetadata(null)); 

有了那麼你可以建立一個綁定使用ContentPresenter,它只是充當您的內容是在傳遞一個佔位符,這個新的內容屬性。這是更容易建立在自ContentControl那裏得到的自定義控件ContentPresenter可以在ControlTemplate中自動連接到內容。

<UserControl x:Class="ShapInteractiveClient.View.SampleTests.jonblind" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     mc:Ignorable="d" 
     d:DesignHeight="300" d:DesignWidth="300"> 

<Grid x:Name="blindGrid" Grid.RowSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
     Opacity="0.82"> 
    <Grid.Background> 
     <LinearGradientBrush EndPoint="0,1" StartPoint="0,0" MappingMode="RelativeToBoundingBox"> 
      <GradientStop Color="#FFA8CBFE" Offset="1"/> 
      <GradientStop Color="Red"/> 
      <GradientStop Color="#FFE1EDFE" Offset="0.147"/> 
     </LinearGradientBrush> 
    </Grid.Background> 

    <ContentPresenter Content="{Binding Path=ContentAreaContent, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" /> 

</Grid> 
</UserControl> 

總的來說這是一個壞主意聲明的UIElement實例作爲資源(更喜歡把他們的模板資源,而不是內部的),但我們可以通過將這個像任何其他控制繞過這個問題很容易。用法是那麼很多更像是一個ContentControl中(如按鈕)看起來像:

<SampleTests:jonblind IsContentVisible="{Binding Path=ShowBlind}"> 
    <SampleTests:jonblind.ContentAreaControl> 
     <StackPanel> 
      <TextBox VerticalAlignment="Center" HorizontalAlignment="Center" Text="Loading!!!" /> 
      <Button Content="hide me!" Command="{Binding Path=alternateblind}" /> 
     </StackPanel> 
    </SampleTests:jonblind.ContentAreaControl> 
</SampleTests:jonblind> 

您可以從這樣的定製ContentControl中,而不是用戶控件獲得更多的優勢,但有一些額外的複雜性和更好地理解這些概念通常有助於使其正確工作。當您開始堅持使用UserControl時,可以更簡單地獲得您需要完成的工作。

+0

兩個答案都很有意思,明天都會試試。謝謝 – Jon 2011-03-24 21:34:23

2

雖然這不是直接回答你的問題,但你應該把控制裏面的內容,而不是使用一個依賴屬性,更具有可讀性的。而不是使用一個用戶控件的,創建可擴展ContentControl中的一類:

public class jonblind : ContentControl 
{ 
    [Category("jonblind")] 
    public bool IsContentVisible 
    { 
     get { return (bool)GetValue(IsContentVisibleProperty); } 
     set { SetValue(IsContentVisibleProperty, value); } 
    } 

    public static readonly DependencyProperty IsContentVisibleProperty = DependencyProperty.Register("IsContentVisible", typeof(bool), typeof(jonblind), 
     new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIsOverlayContentVisibleChanged))); 

    private static void OnIsOverlayContentVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     jonblind blind = d as jonblind; 
     if(blind != null) 
      SetVisibility(blind); 
    } 

    private static void SetVisibility(jonblind blind) 
    { 
     blind.blindGrid.Visibility = blind.IsContentVisible ? Visibility.Visible : Visibility.Hidden; 
    } 
} 

然後用一種風格來指定內容

<Style TargetType="control:jonblind"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="control:jonblind"> 
       <Grid> 
        <Grid.Background> 
         <LinearGradientBrush EndPoint="0,1" StartPoint="0,0" MappingMode="RelativeToBoundingBox"> 
          <GradientStop Color="#FFA8CBFE" Offset="1"/> 
          <GradientStop Color="Red"/> 
          <GradientStop Color="#FFE1EDFE" Offset="0.147"/> 
         </LinearGradientBrush> 
        </Grid.Background> 
        <ContentControl Content="{TemplateBinding Content}"/> 
       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

最後 - 使用它

<control:jonblind IsContentVisible="{Binding Path=ShowBlind}">    
    <StackPanel> 
     <TextBox VerticalAlignment="Center" HorizontalAlignment="Center" Text="Loading!!!" /> 
     <Button Content="hide me!" Command="{Binding Path=alternateblind}" /> 
    </StackPanel> 
</control:jonblind> 

(實例改編從這個線程:How to create a WPF UserControl with NAMED content

+0

這兩個答案都很有意思,明天都會試試。謝謝 – Jon 2011-03-24 21:33:46

+0

如果我可以排除這兩個答案,我會。謝謝 – Jon 2011-03-25 09:18:49

0

對於任何人遇到類似的問題,這一個也沒有找到答案別的地方:

如果您想將子控件的屬性綁定到一個依賴屬性的用戶控制和後綁定屬性在你的用戶界面,依賴屬性是這樣的:

<Page> 
    <my:usercontrol MyCustomPoperty="{Binding MyData}"/> 
</Page> 

你必須做到以下幾點(我花時間弄清楚):

<UserControl x:Class="my.usercontrol"> 
    <TextBox Text="{Binding MyCustomProperty}"> 
</UserControl> 

在後面的構造函數代碼:

public usercontrol() 
{ 
    InitializeComponent(); 
    (this.Content as FrameworkElement).DataContext = this; 
} 

此設置的DataContext爲您構成控件在用戶控件,那麼這些控件可以綁定到您的自定義依賴項屬性,而同時保持在DataContext你的UI設置(頁在這個例子中)。

現在你的用戶界面更新usercontrols的MyCustomProperty,它返回更新綁定到它的usercontrol中的TextBox。

來源:http://blog.jerrynixon.com/2013/07/solved-two-way-binding-inside-user.html