あなたと同じように、私が始めたばかりで、どのように/何が起こっているのかを理解し、テンプレートを操作したいと思ったとき、多くの試行錯誤が必要でした. 私の調査といくつかのステップバイステップのコンポーネントが、好みに合わせてカスタマイズし、物事がどこから来ているのかを知るのに役立つことを願っています.
まず、新しい「テンプレート スタイル」がどのように機能するかを理解しようとするとき、任意の操作スタイル用の単純なスタンドアロン WPF アプリ (「AMS」) を作成しました。このように、主要なプロジェクトやテーマの残りの試行錯誤中に何かがどのように見えるかを永遠に待つ必要はありません.
そこから、「TestingStyles」という新しい WPF ウィンドウを作成しました。保存/コンパイル、実行、問題ありません。
さて、TestingStyles ウィンドウの "VIEW CODE" に、カスタム クラスで遊んでいるものをすべて入れました。
namespace AMS
{
/// <summary>
/// Interaction logic for TestingStyles.xaml
/// </summary>
public partial class TestingStyles : Window
{
public TestingStyles()
{
InitializeComponent();
}
}
// Enumerator for a custom property sample...
public enum HowToShowStatus
{
ShowNothing,
ShowImage1
}
public class YourCustomButtonClass : Button
{
public YourCustomButtonClass()
{
// auto-register any "click" will call our own custom "click" handler
// which will change the status... This could also be done to simplify
// by only changing visibility, but shows how you could apply via other
// custom properties too.
Click += MyCustomClick;
}
protected void MyCustomClick(object sender, RoutedEventArgs e)
{
if( this.ShowStatus == HowToShowStatus.ShowImage1 )
this.ShowStatus = HowToShowStatus.ShowNothing;
else
this.ShowStatus = HowToShowStatus.ShowImage1;
}
public static readonly DependencyProperty ShowStatusProperty =
DependencyProperty.Register("ShowStatus", typeof(HowToShowStatus),
typeof(YourCustomButtonClass), new UIPropertyMetadata(HowToShowStatus.ShowNothing));
public HowToShowStatus ShowStatus
{
get { return (HowToShowStatus)GetValue(ShowStatusProperty); }
set { SetValue(ShowStatusProperty, value); }
}
}
}
ご覧のとおり、カスタムの「ボタン」クラスは、デフォルトの TestingStyles : Window 宣言の外側の下部にあるため、すべて同じ「プロジェクト」内にあります。
この XAML サンプルでは、"TaskComplete.png" グラフィック ファイルを参照します (これはサンプル目的で、プロジェクトに直接追加する必要があります...サンプル目的の単純なスマイリー フェイスであっても)。それで、このような単純な .png ファイルを作成します... Microsoft ペイントを使用して、目と笑顔で円を描きます。ルートのプロジェクトに保存します (後でパスを設定し、最初に機能させます)。
プロジェクトを保存して再コンパイルします。これにより、XAML テンプレートの定義を開始したときに、新しい "クラス" (ボタン) が何であるかをプロジェクトが公に認識できるようになります。
ここで、TestingStyles デザイナーに戻り、分割画面にして、デザイナーと XAML マークアップの両方を表示できるようにします...次のように置き換えるだけです...
<Window x:Class="AMS.TestingStyles"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:AMS"
Title="TestingStyles" Height="300" Width="300" >
<Window.Resources>
<!-- Build a "Style" based on an anticpated target control type of YourCustomButtonClass.
per the "my:" reference, the "my" is an "alias" to the xmlsn:my in the declaration above,
so the XAML knows which library to find such control. In this case, I've included within
the actual forms's 'View Code' as a class at the bottom.
As soon as you assign an "x:Key" reference, its like its telling XAML to make this a PRIVATE
style so you don't reference it explicitly (yet)
-->
<Style TargetType="my:YourCustomButtonClass" x:Key="keyYourCustomButtonClass">
<!-- put whatever normal "settings" you want for your common look / feel, color -->
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="0,0,1,1"/>
<Setter Property="Width" Value="100" />
<Setter Property="Height" Value="30" />
<!-- Now, for the template of the button. Things can get really crazy here
as you are now defining what you want the "button" to look like, borders,
content, etc. In this case, I have two borders to give the raise/sunken effect
of a button and it has its own colors -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button" >
<!-- The x:Name references used during triggers to know what it is "applying" changes to -->
<Border x:Name="BorderTopLeft"
BorderBrush="Gainsboro"
BorderThickness="0,0,1.5,1.5">
<Border x:Name="BorderBottomRight"
BorderBrush="Gray"
BorderThickness="1.5,1.5,0,0">
<!-- Now, what control type do you want the button to have...
Ex: You could use a grid (as I have here), stack panels, etc -->
<Grid Background="LightBlue" >
<!-- I'm defining as two columns wide, one row tall.
First column fixed width 20 pixels example for an image -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20px" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<!-- Now, create the controls I want available within my "template".
when assigned with "x:Name", thats like a property withing the template
that triggers can associate and update to. -->
<Image x:Name="btnImage"
Grid.Row="0" Grid.Column="0"
Stretch="None"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Source="TaskComplete.png"
Visibility="Visible" />
<!-- and also have the text for the button to show the user -->
<TextBlock x:Name="txtNewBtn"
Grid.Row="0" Grid.Column="1"
Padding="5"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{TemplateBinding Content}" />
<!-- The "{TemplateBinding Content}" means to set the text based on
the "CONTENT" property of the original button and not use a fixed value -->
</Grid>
</Border>
</Border>
<!-- Now, some triggers for the button itself... some can be property based, others data-based -->
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="true">
<!-- What properties do we want to change when user CLICKS
on the button, give the "EFFECT" of click down/up by
changing the "Margin" and border thicknesses... -->
<Setter Property="Margin" Value="1,1,0,0"/>
<!-- Notice the "TargetName" below referring to the x:Name I've applied in template above
so when the user clicks on the button, it changes the border thickness properties of
each to give the effect of a normal button clicking. I'm widening one border, shrinking other -->
<Setter TargetName="BorderTopLeft" Property="BorderThickness" Value="2.5,2.5,0,0"/>
<Setter TargetName="BorderBottomRight" Property="BorderThickness" Value="0,0,.5,.5"/>
</Trigger>
<!-- Here, I have a custome property on the class for "ShowStatus". The binding is to itself
regardless of how many instances of this type of "button" are on a given form
First trigger happens when the value is changed to "ShowNothing", but can also change
when set to "ShowImage1" or other as you may need applicable
-->
<DataTrigger Binding="{Binding Path=ShowStatus, RelativeSource={RelativeSource Self}}" Value="ShowNothing">
<Setter TargetName="btnImage" Property="Visibility" Value="Hidden"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=ShowStatus, RelativeSource={RelativeSource Self}}" Value="ShowImage1">
<Setter TargetName="btnImage" Property="Visibility" Value="Visible"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- NOW, we can expose any instance of "YourCustomButtonClass" button to use the style based on definition above
any instance of such YourCustomButtonClass will automatically reflect this style / look -->
<Style TargetType="my:YourCustomButtonClass" BasedOn="{StaticResource keyYourCustomButtonClass}" />
</Window.Resources>
<Grid>
<my:YourCustomButtonClass Content="Button" VerticalAlignment="Top" ShowStatus="ShowImage1" />
</Grid>
</Window>
これにより、独自のテンプレートを定義し、要素がどのように結び付き始めるかをすぐに始めることができます。このサンプルを実行すると、色、余白、パディングなどをテンプレートに変更すると、コンポーネントがコントロールに与える視覚的な影響がすぐにわかります。
壁に頭をぶつけずに楽しんでください...
ところで、これが機能したら、スタイル要素を
<Window.Resources>
</Window.Resources>
これを Windows リソース ディクショナリに配置して、このテスト フォームだけでなく、プロジェクト全体に適用できるようにします。