私はこのXAMLを持っています:
<dxb:BarStaticItem>
<TextBlock Text="{Binding MyStatusBarText}"></TextBlock>
</dxb:BarStaticItem>
ただし、次のエラーが発生します。
Cannot add content to an object of type BarStaticItem
レンダリングされたアイテムの色やスタイルを変更するなど、これを修正するにはどうすればよいですか?
私はこのXAMLを持っています:
<dxb:BarStaticItem>
<TextBlock Text="{Binding MyStatusBarText}"></TextBlock>
</dxb:BarStaticItem>
ただし、次のエラーが発生します。
Cannot add content to an object of type BarStaticItem
レンダリングされたアイテムの色やスタイルを変更するなど、これを修正するにはどうすればよいですか?
と仮定するBarStaticItem
とUserControl
...
1 つの部分的な cs ファイルでコード ビハインドを使用しています。ここでは、(ほぼ) すべてが行われ、代わりにObservableCollection
of (または必要な要素) が使用されます。UIElement
1) という名前の関連する部分クラスを作成しBarStaticItem.Children.cs
、必要な名前空間を追加します。
using System.Collections.ObjectModel; // ObservableCollection.
using System.Collections.Specialized; // NotifyCollectionChangedEventHandler.
using System.Windows.Markup; // [ContentProperty()]
2)ContentProperty
部分クラス宣言の上にフラグを追加してから、 Children
Property 宣言を追加します。
namespace YourNamespace.SubNamespace
{
[ContentProperty("Children")] // <- here !
public partial class BarStaticItem
// (This is the related BarStaticItem.Children.cs file)
{
/// <summary>
/// Gets the Children Property of this BarStaticItem.
/// </summary>
public ObservableCollection<UIElement> Children { get; private set; }
}
}
3) 次に、cs ファイルのプライベート メソッドでObservableCollection プロパティの初期化子を作成します。
private void RegisterChildrenObservation()
{
Children = new ObservableCollection<UIElement>();
Children.CollectionChanged +=
new NotifyCollectionChangedEventHandler(Children_CollectionChanged);
}
4) カスタム UI Element のコンストラクターでその初期化子を呼び出します。
namespace YourNamespace.SubNamespace
{
public partial class BarStaticItem : UserControl
// (This is the base BarStaticItem.xaml.cs file)
{
public BarStaticItem()
{
InitializeComponent();
RegisterChildrenObservation(); // <- here !
}
}
}
5)イニシャライザで呼び出したメソッド ハンドラを宣言することにより、BarStaticItem.Children.cs ファイルでChildren コレクションの動作を処理します。
これは単なる形式的な手順です。全体を理解すれば、xaml だけで行うよりも多くのシナリオを作成できることがわかります。まず、ここで重要なのは 2 つの状態だけです。
NotifyCollectionChangedAction.Add
NotifyCollectionChangedAction.Remove
private void Children_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
{
foreach (UIElement currentElement in e.NewItems)
{
MyChildContainer.Children.Add(currentElement);
}
break;
}
case NotifyCollectionChangedAction.Move:
{
break;
}
case NotifyCollectionChangedAction.Remove:
{
foreach (UIElement currentElement in e.OldItems)
{
MyChildContainer.Children.Remove(currentElement);
}
break;
}
case NotifyCollectionChangedAction.Replace:
{
break;
}
case NotifyCollectionChangedAction.Reset:
{
break;
}
default:
{
break;
}
}
}
6) これでほぼ完了ですが、BarStaticItem.xaml ファイルで UIElement を作成して名前を付け、追加した UIElements を含める必要があります。
<UserControl ...>
<Grid
x:Name="MyChildContainer"><!-- HERE ! -->
</Grid>
</UserControl>
その後、完了し、XAML で BarStaticItem に任意の子要素を直接追加することができます。
<dxb:BarStaticItem>
<TextBlock Text="{Binding MyStatusBarText}"></TextBlock>
</dxb:BarStaticItem>
..そして、それはで定義され、名前が付けられたTextBlock
に着陸します。DockPanel または StackPanel を使用できます。子要素がそのタイプに基づいてどのコンテナーに移動するかを決定したり、場合によっては (依存関係) プロパティを更新したりできます。Grid
MyChildContainer
BarStaticItem.xaml
NotifyCollectionChangedAction.Add
private void Children_CollectionChanged(
object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
{
foreach (UIElement currentElement in e.NewItems)
{
if (currentElement.GetType() == typeof(TextBlock))
{
TextBlock currentTextBlock = (TextBlock)currentElement;
// Manipulate your TextBlock...
HeaderTextBlockContainer.Children.Add(currentElement);
}
else if (currentElement.GetType() == typeof(Button))
{
FooterButtonsDockPanel.Children.Add(currentElement);
DockPanel.SetDock(currentElement, Dock.Right);
}
else
{
MainContentContainer.Children.Add(currentElement);
}
ContentDefined = true; // Custom Property.
}
//...
DV あなたは私じゃない
この XAML は正常に動作しますが、制限があります (表示されるテキストの色を要求どおりに設定することはできません)。
<dxb:BarStaticItem
Content="{Binding MyStatusBarText}">
</dxb:BarStaticItem>
この特定のコントロールにより、ContentTemplate
. これを使用して、コンテンツのスタイルを設定できます。
<dxb:BarStaticItem
ContentTemplate="????">
</dxb:BarStaticItem>
まず、 in を定義DataTemplate
しWindow.Resources
ます。これが私たちContentTemplate
が指摘することです:
<Window.Resources>
<DataTemplate x:Key="MyStatusBarContentTemplate">
<!-- As the DataContext of a resource does not default to the window, we have to use RelativeSource to find the window. -->
<TextBlock Name="MyText"
Text="{Binding Path=MyStatusBarText,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window}}">
</TextBlock>
</DataTemplate>
</Window.Resources>
のDataContext
はDataTemplate
XAML の残りの部分とは異なるため、XAML を省略するRelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}
とバインディングが正しく機能しません。それ以外は、コントロールのコンテンツをレンダリングするために使用できるテンプレートを定義するだけです。
次に、コントロールを this に向けDataTemplate
ます。
<dxb:BarStaticItem
ContentTemplate="{DynamicResource MyStatusBarContentTemplate}">
</dxb:BarStaticItem>
カスタム データ テンプレートを定義したので、やりたいことが何でもできます。たとえばConverter
、ステータス バーにテキストが含まれている場合にテキストを赤く着色する を追加できますError
(それ以外の場合は不可能でした)。
DataTemplate
この回答は、 を使用してほとんどのコントロールのカスタム コンテンツを表示する方法も示しています。
アップデート
Window のリソースで を定義するのではなく、DataTemplate
のリソースとして定義しましたBarStaticItem
。これにより、関連する項目が XAML にまとめられます。
この特定の XAML は、テキストに文字列が含まれている場合、ステータス バーのテキストが自動的に赤くError
なり、ステータス バーのテキストに自動的に時間のプレフィックスが付けられることを意味します。コンバーターの C# コードを投稿してほしい場合はお知らせください。
<dxb:BarStaticItem
ContentTemplate="{DynamicResource MyStatusBarContentTemplate}">
<dxb:BarStaticItem.Resources>
<DataTemplate x:Key="MyStatusBarContentTemplate">
<!-- As the DataContext of a resource does not default to the window, we have to use RelativeSource to find the window. -->
<TextBlock Name="MyText"
Foreground="{Binding ElementName=MyText, Path=Text, Converter={StaticResource ColorRedIfTextContainsError}}"
Text="{Binding Path=SettingsGlobalViewModel.StatusBarText,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window},
Converter={StaticResource PrefixStringWithTime}}">
</TextBlock>
</DataTemplate>
</dxb:BarStaticItem.Resources>
</dxb:BarStaticItem>