2016-05-02 4 views
1

私はボタンのカスタムコントロールを使用して次のコードをリファクタリングしたいと思います。テキストとアイコンのあるボタンのWPFカスタム/ユーザーコントロール。どちらを選ぶべきですか?

XAMLファイル:背後LoginWindow.xaml

<Button Grid.Column="0" Style="{DynamicResource BlackLoginButton}" Click="btnLogin_Click" IsDefault="True"> 
    <DockPanel> 
     <TextBlock Text="text1" VerticalAlignment="Center"/> 
     <Image Source="../../../Assets/Images/apply.png" Style="{StaticResource ImageButton}" /> 
    </DockPanel> 
</Button> 

コード:

<local:CustomButton> 
    Grid.Column="0" 
    IsDefault="True" 
    Style="{DynamicResource BlackLoginButton}" 
    Click="btnLogin_Click" 
    Text="ciao" 
    Image="../../../Assets/Images/apply.png"> 
</local:CustomButton> 

私が使用しよう:私は特に、私はこのような構造を持っているしたいと思いますLoginWindow.xaml.cs

private void btnLogin_Click(object sender, EventArgs e) 
{ 
    Login(); 
} 

カスタムコントロールとユーザーコントロールの両方。ここで

は私のUserControl XAML

<UserControl x:Class="foo.View.CustomUserControl.IconButton" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      DataContext="{Binding RelativeSource={RelativeSource Self}}"> 
    <Button Style="{DynamicResource BlackLoginButton}"> 
     <DockPanel> 
      <TextBlock VerticalAlignment="Center" Text="{Binding ElementName=Button, Path=Text}" /> 
      <Image Source="{Binding ElementName=Button, Path=Image}" Style="{StaticResource ImageButton}" /> 
     </DockPanel> 
    </Button> 
</UserControl> 

そして、背後にあるコードです:

using System.Windows; 
using System.Windows.Media; 

namespace Mhira3D.View.CustomUserControl 
{ 
    public partial class IconButton 
    { 
     public static DependencyProperty ClickProperty = DependencyProperty.Register("Click", typeof(RoutedEventHandler), 
      typeof(IconButton)); 

     public static DependencyProperty ImageProperty = DependencyProperty.Register("Image", typeof(ImageSource), 
      typeof(IconButton)); 

     public static DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(IconButton)); 

     public IconButton() 
     { 
      InitializeComponent(); 
     } 

     public RoutedEventHandler Click 
     { 
      get { return (RoutedEventHandler) GetValue(ClickProperty); } 
      set { SetValue(ClickProperty, value); } 
     } 

     public ImageSource Image 
     { 
      get { return (ImageSource) GetValue(ImageProperty); } 
      set { SetValue(ImageProperty, value); } 
     } 

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

この構造の主な問題は、私はButtonプロパティを使用することができないということです(私はボタンから継承していませんでした)、たとえば、私はIsDefaultを使用できません。

私はそれがこの(THI例では、私が唯一Imageプロパティを置く)のように、より良い方法でボタンプロパティを使用して、代替使用CustomControlことができると思います:

public class IconButtonCustom : Button 
{ 
    static IconButtonCustom() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(IconButtonCustom), new FrameworkPropertyMetadata(typeof(IconButtonCustom))); 
    } 
    public ImageSource Image 
    { 
     get { return GetValue(SourceProperty) as ImageSource; } 
     set { SetValue(SourceProperty, value); } 
    } 
    public static readonly DependencyProperty SourceProperty = 
     DependencyProperty.Register("Image", typeof(ImageSource), typeof(IconButtonCustom)); 
} 

とスタイルでGeneric.xaml

<Style TargetType="{x:Type customUserControl:IconButtonCustom}" BasedOn="{StaticResource BlackLoginButton}"> 
     <Setter Property="Template"> 
      <Setter.Value> 
      <ControlTemplate TargetType="{x:Type customUserControl:IconButtonCustom}"> 
       <Border Background="{TemplateBinding Background}" 
         BorderBrush="{TemplateBinding BorderBrush}" 
         BorderThickness="{TemplateBinding BorderThickness}"> 
        <DockPanel> 
         <TextBlock VerticalAlignment="Center" Text="{Binding ElementName=Button, Path=Text}" /> 
         <Image Source="{Binding ElementName=Button, Path=Image}" Style="{StaticResource ImageButton}" /> 
        </DockPanel> 
       </Border> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

今、私はいくつかの質問を持っている:

  1. カスタムボタンの作成に適した方法はどれですか?
  2. 両方のメソッドを使用すると、実際にはSystem.Windows.Markup.XamlParseExceptionを取得しましたが、WPFは文字列btnLogin_Clickを関数Clickに変換できないため、クリック機能のマッピングに問題があります。
  3. Generic.xamlは一度も使用していませんが、私の例は正しいですか、何らかの方法で改善する必要がありますか?
+0

インスタンスごとに異なるイメージを渡す方法を探していますか? –

+0

異なる画像、テキスト、クリック機能;) – Rowandish

+0

カスタムコントロールを追加する特別な理由はありますか?ボタンスタイルテンプレートだけですべてを行うことができるからです。 –

答えて

1

Alrighty、ほとんどのフレームワーク要素は、私たちが行くと、追加の依存関係プロパティを宣言しなくても、テンプレートに何かバックピギーする方法を使用することができますこのようなインスタンスのために存在するTagと呼ばハンディダンディ性質を持っているようにそのような。

我々は(ボタン - を右クリック>編集テンプレート - >コピーを編集します)デフォルトButtonスタイルテンプレートを取るのであれば、私たちは、一般的に、任意のCLRオブジェクトを渡しますそこにContentPresenterを参照してください。だから、私たちはあなたのテキスト、またはあなたが欲しいものがあればそれが良いです。

あなたの目標を達成するための複数のオプションが用意されました。 1つは、あなたの2つの要素をこの方法で擬似的に渡すことです。

<Button> 
    <StackPanel Orientation="Horizontal"> 
    <TextBlock/> 
    <Image/> 
    </StackPanel> 
</Button> 

これはちょっと面倒です。だから我々はStyleテンプレートオプションに移り、代わりにこのようなことをします。

<Style x:Key="SpecialButtonStyle" TargetType="{x:Type Button}"> 
    <!-- We set a default icon/image path for the instance one isn't defined. --> 
    <Setter Property="Tag" Value="../../../Assets/Images/apply.png"/> 
    <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/> 
    <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/> 
    <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/> 
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> 
    <Setter Property="BorderThickness" Value="1"/> 
    <Setter Property="HorizontalContentAlignment" Value="Center"/> 
    <Setter Property="VerticalContentAlignment" Value="Center"/> 
    <Setter Property="Padding" Value="1"/> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type Button}"> 
       <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true"> 
        <Grid> 
         <Grid.ColumnDefinitions> 
          <ColumnDefinition Width="Auto"/> 
          <ColumnDefinition Width="Auto"/> 
         </Grid.ColumnDefinitions> 
         <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> 
      <!-- This is where we've added an Image to our Button with it's source bound to Tag. PS - In everything else like Silverlight, WP, UWP, Embedded etc, it's just {TemplateBinding Tag} --> 
         <Image Grid.Column="1" Source="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}"/> 
        </Grid> 
       </Border> 
       <ControlTemplate.Triggers> 
        <Trigger Property="IsDefaulted" Value="true"> 
         <Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/> 
        </Trigger> 
        <Trigger Property="IsMouseOver" Value="true"> 
         <Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/> 
         <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/> 
        </Trigger> 
        <Trigger Property="IsPressed" Value="true"> 
         <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/> 
         <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/> 
        </Trigger> 
        <Trigger Property="IsEnabled" Value="false"> 
         <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/> 
         <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/> 
         <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/> 
        </Trigger> 
       </ControlTemplate.Triggers> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

お知らせそれに追加Image要素は、デフォルトの画像何ができるかに文字列のパスを指定して最上部のセッターと一緒に{TemplateBinding Tag}からSourceセットです。

これで、私たちがやることができるインスタンスになりました。

<Button Content="Blah Blah Blah" Click="Click_Handler" 
     Style="{StaticResource SpecialButtonStyle}"/> 

...デフォルトのアイコンとクリックハンドラを持つボタンが表示されます。それ以外は、各インスタンスごとに異なるアイコンを表示する必要があります。だから私たちは何かをすることができます。

<Button Content="Blah Blah Blah" 
     Click="Click_Handler" 
     Tag="../../../Assets/Images/DIFFERENTIMAGE.png" 
     Style="{StaticResource SpecialButtonStyle}"/> 

まだそれほど気が進まないようです。だから私たちはそれをさらに進めて資産列をリソースにすることができました。 SYS」プレフィックスを、あなたはこれを行うことができます。

<sys:String x:Key="imageONE">../../../Assets/Images/imageONE.png</sys:String> 
<sys:String x:Key="imageTWO">../../../Assets/Images/imageTWO.png</sys:String> 
<sys:String x:Key="imageTHREE">../../../Assets/Images/imageTHREE.png</sys:String> 

をこれは私たちにいくつかの利点をないものを、より簡単にメンテナンスをする場合には、ファイルのパスを変更する必要があります:あなたはのxmlns `のようなものとして、辞書にmscorlib名前空間を追加します。これらのアイコンのうちの1つのアイコンの名前/名前は、ただ一つの場所で行うことができ、すべてのインスタンスを継承します。各インスタンスを追跡する代わりに、ハードで設定します。 、今私たちのButtonインスタンスは次のようになります。

<Button Content="Blah Blah Blah" 
     Click="Click_Handler" 
     Tag="{StaticResource imageTWO}" 
     Style="{StaticResource SpecialButtonStyle}"/> 

ほら、あなたが行っている、あなたが考慮しなければならないが、別の観測を、あなたのです。ファイルパス。私は間違いなく代わりにPack Uriを使用します。あなたのパスが正しいし、イメージのビルドアクションも設定されている限り、あなたは設定する必要があります。

これがうまくいくと、歓声が上がります。

+0

データ変換に関する問題が見つかりました:(https://social.msdn.microsoft.com/Forums/vstudio/en-US/edec50f6-d1c7-4891-a814-a9c6f154baf9/binding-image-source-with-templatebinding- in-xaml?forum = wpf)、最後に修正はSource = "{Binding Path = Tag、RelativeSource = {RelativeSource TemplatedParent}}"でした。あなたは答えを修正することができますし、私はそれを受け入れます;) – Rowandish

+0

@Rowandishああ、WPF、それ以外のものは '{TemplateBindingタグ}'ですが、解決してうれしいです。 :) –