コード ビハインドを導入することで、追加の NameScope を作成しました。InitializeComponent() を呼び出した後に NameScope をクリアすることで、実行時にこの余分な NameScope を削除できます。
public ElementBorder()
{
InitializeComponent();
NameScope.SetNameScope(this, null);
...
}
これは機能しますが、最善の解決策ではありません。UserControl のスタイルを作成する方がよいでしょう。
これを行うには、サブクラスを使用する場合と使用しない場合の 2 つの方法があります。
サブクラスで
ElementBorder サブクラスを作成し、デフォルト スタイルをオーバーライドします。InitializeComponent() を呼び出さないでください。
public class ElementBorder
{
static ElementBorder
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ElementBorder), new FrameworkPropertyMetadata(typeof(ElementBorer)));
}
// any additional implementation
}
タグを含める代わりに、xaml ファイルで、必要な設定のスタイルを含む ResourceDictionary を作成します。
<ResourceDictionary xmlns=... >
<Style TargeType="{x:Type my:ElementBorder}">
<Setter Property="BorderThickness" Value="4" />
...
<MergeDictionary> タグを使用して、この ResourceDictionary を app.xaml または themes/Generic.xaml で定義されたものにマージします。
別のファイルを作成する代わりに、app.xaml の ResourceDictionary にスタイルを配置するだけでよいことに注意してください。
これを使用することは、元の ElementBorder を使用することと同じです。
<my:ElementBorder>
<StackPanel ...
サブクラスなし
これにより、必要なコードが少なくなります。前と同じように Style を ResourceDictionary に配置するだけです。ただし、ax:Key を指定し、Border をターゲット タイプとして使用します。
<ResourceDictionary>
<Style x:Key="ElementBorderStyle" TargeType="{x:Type Border}">
<Setter Property="BorderThickness" Value="4" />
...
これは次のように使用できます。
<Border Style="{StaticResource ElementBorderStyle}">
<StackPanel ...
すべての境界線に新しいスタイルを適用したい場合は、さらに簡単です。x:Key を省略して、Border を TargetType として使用するだけです。
<ResourceDictionary>
<Style TargeType="{x:Type Border}">
<Setter Property="BorderThickness" Value="4" />
...
これにより、すべてのボーダーがスタイルを取得するようになるため、次のように記述できます。
<Border>
<StackPanel ...
以下のコメントで尋ねられた追加の質問への回答
BorderBrush を Background と同じに設定するには:
<Style TargeType="{x:Type Border}">
<Setter Property="BorderBrush" Value="{Binding Background, RelativeSource={RelativeSource Self}}" />
...
子の背景をボーダーの背景に設定するには: 子の背景色が設定されていない限り、ボーダーの背景色が透けて見えるため、通常は必要ありません。唯一の例外は、負のマージンまたは RenderTransform の状況で、子が包含境界内に完全にレンダリングされない場合です。その場合、子の Background を Border の Background にバインドする必要があります。これは、添付プロパティを使用せずに BorderBrush に適用されたスタイルでは実行できません。ただし、スタイルなしで問題がなければ:
<Border x:Name="myBorder"> <!-- Style applied here -->
<StackPanel Background="{Binding Background, ElementName=myBorder}" ...
これは、名前のないボーダーで行うこともできます{Binding Background, RelativeSource={RelativeSource FindAncestor,Border,1}。
スタイルで完全に実行する場合は、コードを追加する必要があります。基本的に、「MyBindingTools.BindChildBackgroundToMyBackground」のような名前の添付プロパティを持つクラスを作成します。PropertyChangedCallback を追加して、そのプロパティが「true」に設定されている場合、基本的に子にバインディングが作成されるようにします。
BindingOperations.SetBinding(border, BackgroundProperty, new Binding("Background") { Source = this });
さらに、Border の Child プロパティを監視して、バインディングが変更されたときにバインディングを新しい Child に追加し、古い Child (存在する場合) から削除できるようにする必要があります。
ただし、本当に必要でない限り、これを行うことはお勧めしません。特定の状況では、子を手動でバインドするか、Border と子コントロールの両方を含むテンプレートを作成することができます。私が説明したように、これらのいずれかが添付プロパティを作成するより良い解決策になります。