0

独自の Border クラスを作成してコントロールに挿入しようとしましたが、境界内のすべてに名前を割り当てることができないようです:

..
<my:ElementBorder>
        <StackPanel Name="ifBlock" Background="#E0E8FF" />
</my:ElementBorder> 
..

どうすればこれを回避できますか? そのために何らかの形でテンプレートを使用できますか?

編集: わかりにくかったことを申し訳ありません。はい、Border を独自の XAML ファイルでサブクラス化し、上記のコードでこのコンパイラ エラーが発生しました。

エラー 2 要素 'StackPanel' に Name 属性値 'ifBlock' を設定できません。「StackPanel」は、別のスコープで定義されたときにすでに名前が登録されている要素「ElementBorder」のスコープの下にあります。

私の ElementBorder クラスの内容はあまり興味深いものではありませんが、とにかく投稿します。

<Border x:Class="DVPE.ElementBorder"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    BorderThickness="4" 
    CornerRadius="4">
</Border>
4

3 に答える 3

3

コード ビハインドを導入することで、追加の 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 と子コントロールの両方を含むテンプレートを作成することができます。私が説明したように、これらのいずれかが添付プロパティを作成するより良い解決策になります。

于 2009-11-08T23:03:12.733 に答える
0

これは、Namescopeの問題として知られています。詳細については、こちらを確認してください:http: //dotnet.dzone.com/news/c-and-wpf-namescope-my-name-is

于 2009-11-08T08:11:49.157 に答える
0

名前のスコープは、論理ツリーを検索することによって検出されます。

(Border クラスをサブクラス化するのではなく) 独自の Border をロールした場合、名前スコープの問題は次の原因で発生する可能性があります。

  • AddLogicalChild の呼び出しに失敗しました
  • LogicalChildren 列挙体を正しくオーバーライドしていない

一方、既存の Border (または任意の Decorator) をサブクラス化すると、論理ツリーが処理されます。

これは、ボーダーに明示的な NameScope が設定されている場合にも発生する可能性があります。その場合、名前は割り当てられますが、FindName は Window/UserContol/template レベルでそれを見つけられません。

ElementBorder クラスの関連セクションを投稿すると、より良い回答が得られる可能性があります。

于 2009-11-07T18:02:27.570 に答える