2016-03-01 162 views
0

首先,這是在.NET 4.0中,因爲它必須是。我知道.NET的後續版本中已經修復了一些錯誤,所以如果這是一個實際的.NET錯誤,我想我將不得不忍受使用似乎沒有這個問題的用戶控件。WPF自定義控件按鈕內容缺少多個按鈕

我在WPF中創建了一個自定義控件庫,以便在第三方軟件中使用可定製的按鈕。但是,我似乎遇到了一個問題,即使用多個按鈕導致所有按鈕的內容都會丟失。我已經在SNOOP中確認了這個問題。內容只是不存在。 SNOOP樹的內容與主持人一樣遠,除此之外沒有任何內容,除了一個有內容的按鈕。我創建了一個非常簡單的問題示例。

我的圖書館Generic.xaml如下:

<ResourceDictionary 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:controls="clr-namespace:CustomControlsLibrary.Controls"> 

<Style x:Key="CustomButtonStyle" TargetType="{x:Type controls:CustomButton}"> 
    <Setter Property="FontSize" Value="16" /> 
    <Setter Property="FontWeight" Value="Bold" /> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type controls:CustomButton}"> 
       <Border CornerRadius="{TemplateBinding CornerRadius}" BorderThickness="3" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}"> 
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" ContentSource="Content" /> 
       </Border> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

<Style x:Key="Button1Style" TargetType="{x:Type controls:Button1}" BasedOn="{StaticResource CustomButtonStyle}" > 
    <Setter Property="CornerRadius" Value="4" /> 
    <Setter Property="BorderBrush" Value="White" /> 
    <Setter Property="Height" Value="40" /> 
    <Setter Property="Width" Value="100" /> 
    <Setter Property="Foreground" Value="White" /> 
    <Setter Property="Content"> 
     <Setter.Value> 
      <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=controls:Button1}, Path=Text}" /> 
     </Setter.Value> 
    </Setter> 
</Style> 

兩個控制類如下:

的CustomButton:

public class CustomButton : Button 
{ 
    public static readonly DependencyProperty CornerRadiusProperty = 
     DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(CustomButton), new FrameworkPropertyMetadata(new CornerRadius(0))); 

    public CornerRadius CornerRadius 
    { 
     get { return (CornerRadius)GetValue(CornerRadiusProperty); } 
     set { SetValue(CornerRadiusProperty, value); } 
    } 

    static CustomButton() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomButton), new FrameworkPropertyMetadata(typeof(CustomButton))); 
    } 
} 

Button1的:

public class Button1 : CustomButton 
{ 

    public static readonly DependencyProperty TextProperty = 
     DependencyProperty.Register("Text", typeof(string), typeof(Button1), new FrameworkPropertyMetadata("")); 

    public string Text 
    { 
     get { return (string)GetValue(TextProperty); } 
     set { SetValue(TextProperty, value); } 
    } 

    static Button1() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(Button1), new FrameworkPropertyMetadata(typeof(Button1))); 
    } 
} 

我然後創建只是一個主窗口一個簡單的WPF應用程序與MainWindow.xaml所有的邏輯:

<Window x:Class="CustomControlLibraryTestApp.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:controls="clr-namespace:CustomControlsLibrary.Controls;assembly=CustomControlsLibrary" 
    Title="MainWindow" Height="350" Width="525" Background="DarkGray"> 

<Window.Resources> 
    <ResourceDictionary Source="pack://application:,,,/CustomControlsLibrary;component/Themes/Generic.xaml" /> 
</Window.Resources> 

<StackPanel> 
    <controls:Button1 Style="{StaticResource Button1Style}" Background="Red" Text="Button 1" /> 
    <controls:Button1 Style="{StaticResource Button1Style}" Background="Blue" Text="Button 2" /> 
</StackPanel> 

運行時,對按鈕1的含量就不復存在了,而按鈕2看起來很好。從窗口中刪除按鈕2會導致按鈕1看起來像預期的那樣。

正如前面提到的,SNOOP表示當兩個按鈕都存在時,按鈕1的內容不在那裏。

任何想法?

回答

3

我要去了反對意見扔在這裏,開始與馬修·麥克唐納「臨WPF在C#」一帖:

自定義控件仍然構建 您的自定義部件的有效途徑可以在應用程序之間共享,但當您想要增強和定製核心控件時,它們不再是 的要求。 (至 瞭解這種變化是多麼顯着,它有助於指出本書的前身,Pro .NET 2.0 Windows Forms和自定義 C#中的控件有關於自定義控件的九個完整章節和其他章節中的其他示例。在這本書中,你已經將它製作成 它沒有一個自定義控制瞄準!)

簡而言之,就是不需要創建額外的按鈕類來控制模板中已存在的屬性。你可以像使用數據綁定或附加屬性一樣輕鬆地完成這個任務,並且與Blend等工具更加兼容。

爲了說明這裏的關鍵是爲你在你的示例代碼暴露出兩個屬性的輔助類:

public static class ButtonHelper 
{ 
    public static double GetCornerRadius(DependencyObject obj) 
    { 
     return (double)obj.GetValue(CornerRadiusProperty); 
    } 

    public static void SetCornerRadius(DependencyObject obj, double value) 
    { 
     obj.SetValue(CornerRadiusProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for CornerRadius. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty CornerRadiusProperty = 
     DependencyProperty.RegisterAttached("CornerRadius", typeof(double), typeof(ButtonHelper), new PropertyMetadata(0.0)); 


    public static string GetButtonText(DependencyObject obj) 
    { 
     return (string)obj.GetValue(ButtonTextProperty); 
    } 

    public static void SetButtonText(DependencyObject obj, string value) 
    { 
     obj.SetValue(ButtonTextProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for ButtonText. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty ButtonTextProperty = 
     DependencyProperty.RegisterAttached("ButtonText", typeof(string), typeof(ButtonHelper), new PropertyMetadata("")); 

} 

現在馬上就可以創建兩個風格,每一個你的按鈕類型,即綁定內部對這些屬性:

<Style x:Key="RoundedButtonStyle" TargetType="{x:Type Button}" > 
     <Setter Property="Margin" Value="10" /> 
     <Setter Property="HorizontalAlignment" Value="Left" /> 
     <Setter Property="VerticalAlignment" Value="Center" /> 
     <Setter Property="Foreground" Value="White" /> 
     <Setter Property="FontSize" Value="16" /> 
     <Setter Property="FontWeight" Value="Bold" /> 
     <Setter Property="BorderBrush" Value="Red" /> 
     <Setter Property="Background" Value="Red" /> 
     <Setter Property="controls:ButtonHelper.CornerRadius" Value="4" /> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="Button"> 
        <Border CornerRadius="{Binding Path=(controls:ButtonHelper.CornerRadius), 
         RelativeSource={RelativeSource TemplatedParent}}" BorderThickness="3" 
          BorderBrush="{TemplateBinding BorderBrush}" 
          Background="{TemplateBinding Background}"> 
         <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" ContentSource="Content" /> 
        </Border> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 

    <Style x:Key="TextButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource RoundedButtonStyle}"> 
     <Setter Property="BorderBrush" Value="Blue" /> 
     <Setter Property="Background" Value="Blue" /> 
     <Setter Property="controls:ButtonHelper.ButtonText" Value="TextButton" /> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="Button"> 
        <Border CornerRadius="{Binding Path=(controls:ButtonHelper.CornerRadius), 
         RelativeSource={RelativeSource TemplatedParent}}" BorderThickness="3" 
          BorderBrush="{TemplateBinding BorderBrush}" 
          Background="{TemplateBinding Background}"> 
         <TextBlock Text="{Binding Path=(controls:ButtonHelper.ButtonText), 
          RelativeSource={RelativeSource TemplatedParent}}" Background="Transparent" /> 
        </Border> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 

就是這樣!不需要自定義控件,不需要x:由於內容直接在樣式中指定,因此共享,而且它的重量更輕。這裏是正在使用他們的例子:

<UniformGrid Columns="2"> 

    <Button Style="{StaticResource RoundedButtonStyle}" Content="RoundedButton" /> 
    <Button Style="{StaticResource RoundedButtonStyle}" Content="RoundedButton big radius" controls:ButtonHelper.CornerRadius="20"/> 

    <Button Style="{StaticResource TextButtonStyle}" /> 
    <Button Style="{StaticResource TextButtonStyle}" controls:ButtonHelper.ButtonText="TextButton new text"/> 

    <Button Style="{StaticResource TextButtonStyle}" BorderBrush="Green" Background="Green" 
      controls:ButtonHelper.ButtonText="Both text and radius" 
      controls:ButtonHelper.CornerRadius="20" /> 

</UniformGrid> 

和這裏的結果:

enter image description here

我也知道我指定的邊界在每個模板,當然,但也可以通過在邊界內放置內容控件並使用數據模板來設置內容可輕鬆刪除。

+0

終於開始實施你的建議。它工作得很好(特別是對於一些更復雜的風格控制)。謝謝! – GrantA

1

發生了什麼是該樣式實際上只有一個TextBlock實例。將樣式應用於第二個按鈕時,TextBlock實際上會重新添加到新控件。您應該可以通過在TextBlock元素上設置x:Shared="false"來避免這種情況。

+1

不錯!您的修補程序有效,但是x:Shared屬性只能應用於Style本身,而不能應用於TextBlock元素。但將它應用到Button1Style解決了這個問題。謝謝。 – GrantA

+0

啊呀。 x:共享不會出現太多,所以我不記得確切的用法。當你不期望它時,它肯定會令人發狂。 – Eric

+0

同意。我不記得我是否遇到過之前需要的情況,這就是爲什麼我被困在了發生的事情上,以及爲什麼我在網上找不到與我遇到的問題類似的東西。 – GrantA