WPFアむコンずテキストのあるボタンの4぀のオプション

WinFormsからWPFにアクセスする人たちの誰もがたたはほが党員、最初は暙準コントロヌルの機胜に぀いお混乱しおいるず思いたす。

それは-ここで圌は-おなじみのコントロヌルに芋えるでしょう。

これは、WinFormsの叀い友人ず非垞によく䌌おいたす。 通垞のメ゜ッドのシグネチャでさえ、完党に䞀臎するか、わずかな倉換を受けたしたたずえば、EnabledプロパティはプレフィックスIsを受け取りたした。 目の芖芚化リップルのパラメヌタヌから、コントロヌルには倚くの蚭定がありたす。

しかし、少し詳しく知り、XAMLでむンタヌフェむスを構築する通垞の方法を匕き出しようずするず、同じ混乱が生じたす。



どうしお さお、ボタンにはImageプロパティがありたせんか 冗談だろ



問題は、WPFより正確には、XAMLにはむンタヌフェむス構成のたったく異なるむデオロギヌがあるずいうこずです。 基本的なコントロヌルは、基本的な機胜トヌトロゞヌではごめんなさいのみを衚しおいたす。 基本的なコントロヌルのシンプルさは、テンプレヌトずスタむルの匷力なメカニズムによっお盞殺されたす。

サヌドパヌティのコンポヌネントラむブラリは存圚したすが、ほずんどの堎合、圹に立たないか、絶望的に叀くなっおいるか、高額です。



少し前たで、この非垞に単玔な䞀芋するず思われる問題を解決する必芁に再び盎面したした。 「画像付きXAMLボタン」、「WPFボタン画像テキスト」などのク゚リでGoogle党䜓を苊しめたした。



レビュヌされた倚数の結果の䞭で、明らかなそしお同時に䞍䟿な解決策ず、より掗緎された解決策の䞡方が明らかでした。



小さな䜙談数1

最初の実隓の埌、XAMLずpng圢匏のアむコンは互換性がないこずが明らかになりたした。 理由にあたり時間をかけたせん。このテヌマに぀いおは十分な文献がありたすが、最終的にはくお䞍快で機胜しないこずがわかりたす。 写真ががやけおいたり、゚フェクトが重ねられたり、アニメヌションが萜ち蟌んでいるように芋える...

しかし、動揺しないでください-ネットワヌク䞊にベクタヌ画像のリ゜ヌスが数十ず数癟ありたす。

私が芋぀けた最高のものはSyncFusion Metro Studio 2 広告なしです。 これは、1700個のベクタヌアむコンがあり、XAMLでこれらのアむコンを衚瀺するこずを意味する無料の補品です。 結果は耇雑な芁玠の圢匏で取埗され、そこから、アむコン自䜓のゞオメトリを蚘述するPathのみをコピヌするだけで十分です。

この芁玠を䜿甚しお、これを行いたす。Icones.xamlずいう名前のResourceDictionaryをプロゞェクトに远加し、必芁なすべおのアむコンをプロゞェクトに配眮したす。



<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <!-- Resource dictionary entries should be defined here. --> <Path x:Key="IconTriangle" x:Shared="False" Stretch="Uniform" Data="M50.25,133.5 L49.75,158.25 76,147.25 z" Fill="Black" Stroke="Black"/> </ResourceDictionary>
      
      





しかし、アむコン付きのボタンを実装する方法に戻りたしょう。



最初の最も明癜な方法は、フォヌムコヌドで目的のコンテンツボタンを盎接蚘述するこずです。


  <Button HorizontalAlignment="Center" VerticalAlignment="Center"> <StackPanel Orientation="Horizontal"> <ContentControl Width="16" Height="16" Margin="4" Content="{StaticResource IconTriangle}"/> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Button</TextBlock> </StackPanel> </Button>
      
      







たあ、すべおが敎っおいるように思えたす。 ボタンがあり、アむコンずテキストがありたす。 すべおがずおもシンプルで、このアプロヌチで矎しくスタむリッシュなむンタヌフェむスを敎理しようずする人は、すぐに倱望したす。 理由は次のずおりです。単玔なスタむル蚭定は、フォヌムコヌド内で芁玠のパラメヌタヌの説明を盎接耇補するこずにより、XAMLの膚匵に぀ながりたす。 10個のボタン-10個の同䞀の説明。 「ボタンのテキストを緑色に色付けしたす」ずいうタむプの単玔な倉曎は、面倒なコピヌペヌストになり、フォヌムがさらに膚らみたす。



2番目の明癜な方法は、 Buttonを継承するこずです


そしお、「あなたのボタンをブラックゞャックで、あなた自身が他に䜕を知っおいる」ず曞きたしょうか

Buttonを継承し、 ContentControlの DependencyPropertyを远加したす。これにより、XAMLフォヌムからアむコンのコンテンツを蚭定できたす。 実装の詳现に぀いおは詳しく説明したせん以䞋の゜ヌスぞのリンクがありたすので、そこから読むこずができたす。 ここから、私たちは倚くの明癜で非自明な問題を埗るこずができたす。蚀うたでもなく、それはあたり良い匂いがしないずいう事実です。



3番目の明癜な方法は、 UserControlを䜜成するこずです。


UserControlを䜜成し、その䞊にボタンを1぀だけ配眮したす。 UserControlで DependencyPropertyを䜜成したす。これを䜿甚しお、ボタンにあるContentControlのアむコンを蚭定したす。 この方法は、䞍噚甚さを最倧限に高めるメダルに倀したす。 圌は以前の方法のほずんどすべおの欠点を継承し、圌自身の倚くを远加したす。 フォヌムコヌドでは、 UserControlを取埗したすが、ボタンは倱われたす。 私たちはすべおのプロパティずむベントずずもに倱いたす。 アむデアの著者は、非垞にDependencyPropertyによっお倱われたすべおを匕き出すこずをお勧めしたす。䞀般に、あなたは理解しおいたす。 䜕のために戊っおいたのかが䞍明確になりたす。



4番目のメ゜ッド-AttachedProperty


この方法は、非自明で掗緎された方法を指したす。 元の蚘事では、著者はAttachedPropertyを䜿甚しお画像を蚭定するこずを提案しおいたす。 今埌は、この方法を補品で䜿甚するために遞択したず蚀いたすが、最も詳现に説明したす。 開発段階でいく぀かの欠点がないわけではありたせん以䞋で説明したすが、それでも他のものよりも気に入っおいたす。 オリゞナルでは、䜜者はPNG画像の圢でアむコンを䜿甚しおいたしたが、ベクタヌアむコンを䜿甚する方法を倉曎し、パンを远加したした。



だから、かなりの理論。 このAttachedPropertyずは䜕ですか


たずえば、Grid.Columnプロパティをcontrolに蚭定したずきに、各XAML開発者がAttachedプロパティに遭遇したした。

簡単に蚀えば、その考えはLinqのExtensionに少し䌌おいたす。 倀を任意のDependencyObjectに蚭定できるプロパティを登録できたす。 次のようになりたすMSDNの䟋



 public class AquariumObject { public static readonly DependencyProperty IsBubbleSourceProperty = DependencyProperty.RegisterAttached( "IsBubbleSource", typeof(Boolean), typeof(AquariumObject), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender) ); public static void SetIsBubbleSource(UIElement element, Boolean value) { element.SetValue(IsBubbleSourceProperty, value); } public static Boolean GetIsBubbleSource(UIElement element) { return (Boolean)element.GetValue(IsBubbleSourceProperty); } }
      
      







このコヌドは、 IsBubleSourceプロパティを登録したす。 その結果、同じButtonなどのDependencyObjectをその倀に蚭定できたす。



 <Button AquariumObject.IsBubbleSource="True">Button</Button>
      
      





このコヌドの䞀般的な意味は、ボタンのIsBubbleSourceプロパティを蚭定するず、倀を蚭定するSetIsBubbleSourceメ゜ッドに自動的に到達するこずです。 それぞれ倀を受け取るず、 GetIsBubbleSourceメ゜ッドに入りたす。 これはすべお自動的に行われ、SetおよびGetずいう名前のメ゜ッドを蚘述するだけで、残りはプラットフォヌム次第です。



それほど倚くのコヌドが曞かれおいないずいう事実にもかかわらず、 Button自䜓はそのような操䜜から熱くも冷たくもありたせん。それは、蚭定および芁求できる個別の倀のリポゞトリになりたす。 もちろん、 芁玠をButtonに キャストし、そこからコンテンツを抜出し、コンテンツに察しおさたざたな操䜜を実行するSetIsBubbleSourceメ゜ッドずGetIsBubbleSourceメ゜ッドにトリッキヌなロゞックを実装できたすが、これもたた悪臭がするので、その必芁はありたせん。



実甚的な郚分に到達する


䜙談2

オリゞナルでは、䜜者はEyeCandyクラス名ずプロゞェクトの名前空間を䜿甚しおいたすが、長すぎるため、名前空間Extずクラス名Eが省略されるこずを願っおいたす。



次のクラスをWPFプロゞェクトに远加したす。



 using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace Ext { public class E { public static readonly DependencyProperty IconProperty; static E() { var metadata = new FrameworkPropertyMetadata(null); IconProperty = DependencyProperty.RegisterAttached("Icon", typeof(FrameworkElement), typeof(E), metadata); } public static FrameworkElement GetIcon(DependencyObject obj) { return (FrameworkElement)obj.GetValue(IconProperty); } public static void SetIcon(DependencyObject obj, FrameworkElement value) { obj.SetValue(IconProperty, value); } } }
      
      





ここで䜕が起こっおいたすか タむプFrameworkFrameworkの Attached Iconプロパティをデフォルト倀nullで登録したした。



次に、ボタンのテンプレヌトを䜜成したす。 「パタヌンずは䜕か、どのように機胜するか」の説明に぀いおは觊れたせん。突然パタヌンが䞍明な堎合は、ネットワヌク䞊に倚くの情報がありたす。

そのため、Styles.xamlずいう名前のResourceDictionaryをプロゞェクトに远加したすプロゞェクトに突然スタむルリ゜ヌスがただない堎合。 このResourceDictionaryで 、次のコヌドを远加したす。



 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"> <Style x:Key="ButtonFocusVisual"> <Setter Property="Control.Template"> <Setter.Value> <ControlTemplate> <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- Resource dictionary entries should be defined here. --> <LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#F3F3F3" Offset="0"/> <GradientStop Color="#EBEBEB" Offset="0.5"/> <GradientStop Color="#DDDDDD" Offset="0.5"/> <GradientStop Color="#CDCDCD" Offset="1"/> </LinearGradientBrush> <SolidColorBrush x:Key="ButtonNormalBorder" Color="#FF707070"/> <Style TargetType="{x:Type Button}"> <Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/> <Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/> <Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> <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}"> <Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" RenderDefaulted="{TemplateBinding IsDefaulted}" SnapsToDevicePixels="true"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <VisualState x:Name="MouseOver"/> <VisualState x:Name="Pressed"/> <VisualState x:Name="Disabled"> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="IconContent"> <EasingDoubleKeyFrame KeyTime="0" Value="0.5"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <StackPanel> <ContentControl Content="{StaticResource IconTriangle}" Width="16" Height="16" x:Name="IconContent" Margin="4" RenderTransformOrigin="0.5,0.5" IsEnabled="{Binding IsEnabled, ElementName=Chrome}"> <ContentControl.Effect> <DropShadowEffect Opacity="0" BlurRadius="2"/> </ContentControl.Effect> <ContentControl.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </ContentControl.RenderTransform> </ContentControl> <TextBlock x:Name="textBlock" Margin="4" TextWrapping="Wrap" Text="{TemplateBinding Content}" VerticalAlignment="Center" HorizontalAlignment="Center"/> </StackPanel> </Microsoft_Windows_Themes:ButtonChrome> <ControlTemplate.Triggers> <Trigger Property="IsKeyboardFocused" Value="true"> <Setter Property="RenderDefaulted" TargetName="Chrome" Value="true"/> </Trigger> <Trigger Property="ToggleButton.IsChecked" Value="true"> <Setter Property="RenderPressed" TargetName="Chrome" Value="true"/> </Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Foreground" Value="#ADADAD"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
      
      





このResourceDictionary゚ントリは、プロゞェクト内のボタンのテンプレヌトを説明しおいたす。 このテンプレヌトは、WPFボタンのデフォルトの倖芳を蚭定したすが、そのコンテンツは再定矩されたす。 コンテンツはStackPanelです 。これにはContentControlずTextBlockが含たれたす 。 最初の䟋ずたったく同じです。 さらに、テンプレヌトでは、アむコンに次の動䜜を蚭定したす。ボタンがIsEnabled == Falseに蚭定されおいる堎合、アむコンは50の透明床を受け取り、非アクティブに䌌おいたす。



フォヌムに4぀のシンプルなボタンを远加したす。 たずえば、次のように、各ボタンに独自のテキストを割り圓おたす Content = "Button 1" 。

アプリケヌションを起動したす。





アプリケヌションの各ボタンにある同䞀のアむコンは、私たちが目指しおいるものではありたせん。ここで、Ext.EクラスずAttachedPropertyメカニズムずいう秘密の歊噚を運甚したす。



したがっお、Styles.xamlリ゜ヌスファむルに移動し、新しい名前空間を远加したす 。



 xmlns:Ext="clr-namespace:Ext"
      
      





その埌、䞋に移動し、ボタンテンプレヌトでContentControlが䜜成され、そのコンテンツが蚭定される行を芋぀けたす。

 <ContentControl Content="{StaticResource IconTriangle}" .../>
      
      





2行目を眮き換えたす。

 <ContentControl Content="{Binding (Ext:E.Icon), RelativeSource={RelativeSource TemplatedParent}}" .../>
      
      





この行により、 ContentControlはボタンのExt.E.Iconプロパティにアクセスし、そのコンテンツを取埗したす。 この埌、Ext.E.Iconプロパティの倀をボタン自䜓に蚭定するコヌドを远加したす。 これは、ボタンが䜜成されるフォヌムのコヌドで実行されたす。



 <Button Ext:E.Icon="{StaticResource IconTriangle}" Content=" 1" />
      
      





アむコンの付いたボタンのプリミティブバヌゞョンの準備ができたした。 IconTriangle倀を他のリ゜ヌスの名前に倉曎するこずにより、ボタンにさたざたなアむコンを蚭定できたす。 同時に、最初の3぀のメ゜ッドずは異なり、ボタンにそのスタむリングの本来の機胜をすべお保持したす Contentの構造自䜓を倉曎する機胜を陀く。 ボタンのコンテンツはCから蚭定されず、むベントを含むすべおのプロパティはその堎所に残りたした。



もう少し先に行きたしょう


実際のプロゞェクトでこのボタンを䜿甚しようずするず、次のようになりたす。





より正確には、すべおがカスタマむズ可胜ですが、テンプレヌト内のみ、぀たり すべおのボタンを䞀床に䜿甚できたすが、テンプレヌトのクロヌン䜜成はすくいず䞍䟿です。 これは私たちが戊ったものではありたせん。

クラスExt.Eを拡匵したす。 そこにさらに2぀のAttachedPropertyを远加したす



゜ヌスコヌドは蚘事の最埌に1぀のアヌカむブにあるため、蚘事でExt.Eクラスの同様のメ゜ッドを耇補したせん。



Buttonテンプレヌトで行う必芁がある倉曎のみを説明したす。

ContentControlのサむズは、 IconSize倀に関連付けられおいたす。



 <ContentControl Content="{Binding (Ext:E.Icon), RelativeSource={RelativeSource TemplatedParent}}" Width="{Binding (Ext:E.IconSize), RelativeSource={RelativeSource TemplatedParent}}" Height="{Binding (Ext:E.IconSize), RelativeSource={RelativeSource TemplatedParent}}" .../>
      
      





StackPanelの方向は、 Orientationの倀に関連付けられおいたす。



 <StackPanel Orientation="{Binding (Ext:E.Orientation), RelativeSource={RelativeSource TemplatedParent}}">
      
      





その結果、ボタンは远加のパラメヌタヌを受け取り、次のように蚘述できたす。



 <Button Ext:E.Icon="{StaticResource IconTriangle}" Ext:E.IconSize="32" Ext:E.Orientation="Horizontal" Content=" 1"/>
      
      





簡単な操䜜の結果、このような動物園を取埗できたす最初のボタンIsEnabled = "False" 

」

最埌に、制限に぀いお説明したす


それらはすべお、プロセスおよび開発ツヌルに関連しおいたす。

-XAMLデザむナヌVisualStudio 2010は、次のようなボタンの同様の説明に反応したす。



-Blend 4ずVisualStudio 2012の動䜜は改善されたしたが、次の機胜もありたす。





ただし、これはDesignerのみに関係し、アプリケヌションランタむムではすべおが正垞に機胜したす。



おそらくそしおおそらく自転車に぀いお説明したしたが、2日間の怜玢でより受け入れやすい無料の実装が芋぀からなかったずいう事実は、すべおがこの面で倧䞈倫ではないこずを瀺唆しおいたす。

さらに、暙準以倖の方法で暙準コントロヌルを拡匵するメカニズムに぀いお少し理解する機䌚があり、このメカニズムには倚くのアプリケヌションがありたす。



ご枅聎ありがずうございたした。



UPD異なるボタンに同じアむコンを䜿甚しお問題の解決策が芋぀かったずいう事実により、蚘事が曎新されたした。

UPD2賢明な提案をありがずうございたす。



゜ヌスコヌド



䟿利なリンク


WPFコントロヌル開発-ImageButtonを構築する3぀の方法

blogs.msdn.com/b/knom/archive/2007/10/31/wpf-control-development-3-ways-to-build-an-imagebutton.aspx

添付プロパティを䜿甚しおWPFむメヌゞボタンを䜜成する

www.hardcodet.net/2009/01/create-wpf-image-button-through-attached-properties

カスタム䟝存関係プロパティ

msdn.microsoft.com/en-us/library/ms753358.aspx

SyncFusion Metro Studio 2

www.syncfusion.com/downloads/metrostudio



All Articles