[英]WPF - DataTemplate - Using element binding within an attached property
[英]Binding to Nested Element in Attached Property in WPF
我試圖將嵌套在附加屬性內的元素綁定到我的DataContext
,但問題是附加屬性不是邏輯樹的一部分,因此沒有正確設置或綁定到父對象的數據上下文。 依賴屬性(在本例中為Value
)始終為 null。
這是一些示例 XAML
<StackPanel>
<!-- attached property of static class DataManager -->
<local:DataManager.Identifiers>
<local:TextIdentifier Value="{Binding Path=MyViewModelString}" />
<local:NumericIdentifier Value="{Binding Path=MyViewModelInt}" />
<local:NumericIdentifier Value="{Binding Path=SomeOtherInt}" />
</local:DataIdentifiers>
<!-- normal StackPanel items -->
<Button />
<Button />
</StackPanel>
由於實現,這不能是單個附加屬性 - 它需要是一個允許n 個實體的集合。 另一個可接受的解決方案是將標識符直接放在節點中,但我認為如果不將這些元素明確包含在邏輯樹中,這種語法是不可能的。 IE..
<Button>
<local:NumericIdentifier Value="{Binding}" />
<local:TextIdentifier Value="{Binding}" />
<TextBlock>Actual button content</TextBlock>
</Button>
這是DataManager
實現的開始。
[ContentProperty("IdentifiersProperty")]
public static class DataManager
{
public static Collection<Identifier> GetIdentifiers(DependencyObject obj)
{
return (Collection<Identifier>)obj.GetValue(IdentifiersProperty);
}
public static void SetIdentifiers(DependencyObject obj, Collection<Identifier> value)
{
obj.SetValue(IdentifiersProperty, value);
}
public static readonly DependencyProperty IdentifiersProperty =
DependencyProperty.RegisterAttached("Identifiers", typeof(Collection<Identifier>), typeof(DataManager), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIdentifiersChanged)));
}
我已經嘗試讓基類Identifiers
實現Freezable
,希望它可以用於數據和綁定上下文的繼承,但這沒有任何效果(可能是因為它嵌套在另一個層中 - 附加屬性)。
還有幾個關鍵點:
UIElement
,而不僅僅是StackPanel
sIdentifier
不是可視化樹的一部分。 他們沒有也不應該有視覺元素Source
或RelativeSource
用於綁定,因為需要這樣做並不直觀是否可以在標記的這一層綁定到繼承的DataContext
? 我是否需要手動將這些添加到邏輯樹中? 如果是這樣,如何?
謝謝!
除了讓Identifier
從Freezable
繼承之外,您還需要使用FreezableCollection
而不是Collection<Identifier>
作為附加屬性類型。 這將確保繼承鏈不被破壞。
public class Identifier : Freezable
{
... // dependency properties
protected override Freezable CreateInstanceCore()
{
return new Identifier();
}
}
創建自定義集合:
public class IdentifierCollection : FreezableCollection<Identifier> { }
並且,修改附加屬性以使用此集合:
[ContentProperty("IdentifiersProperty")]
public static class DataManager
{
public static readonly DependencyProperty IdentifiersProperty =
DependencyProperty.RegisterAttached(
"Identifiers",
typeof(IdentifierCollection),
typeof(DataManager),
new FrameworkPropertyMetadata(OnIdentifiersChanged));
...
public static void SetIdentifiers(UIElement element, IdentifierCollection value)
{
element.SetValue(IdentifiersProperty, value);
}
public static IdentifierCollection GetIdentifiers(UIElement element)
{
return element.GetValue(IdentifiersProperty) as IdentifierCollection;
}
}
<Window.DataContext>
<local:TestViewModel
MyViewModelInt="123"
MyViewModelString="Test string"
SomeOtherInt="345" />
</Window.DataContext>
<StackPanel x:Name="ParentPanel" ... >
<!-- attached property of static class DataManager -->
<local:DataManager.Identifiers>
<local:IdentifierCollection>
<local:TextIdentifier Value="{Binding Path=MyViewModelString}" />
<local:NumericIdentifier Value="{Binding Path=MyViewModelInt}" />
<local:NumericIdentifier Value="{Binding Path=SomeOtherInt}" />
</local:IdentifierCollection>
</local:DataManager.Identifiers>
<!-- normal StackPanel items -->
<TextBlock Text="{Binding Path=(local:DataManager.Identifiers)[0].Value,
ElementName=ParentPanel, StringFormat=Identifer [0]: {0}}" />
<TextBlock Text="{Binding Path=(local:DataManager.Identifiers)[1].Value,
ElementName=ParentPanel, StringFormat=Identifer [1]: {0}}" />
<TextBlock Text="{Binding Path=(local:DataManager.Identifiers)[2].Value,
ElementName=ParentPanel, StringFormat=Identifer [2]: {0}}" />
</StackPanel>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.