绑定到 WPF 中 Attached 属性 中的嵌套元素
Binding to Nested Element in Attached Property in WPF
我正在尝试将嵌套在附加 属性 内的元素绑定到我的 DataContext
,但问题是附加的 属性 不是逻辑树的一部分,并且因此没有正确设置或绑定到父对象的数据上下文。依赖项 属性,在本例中 Value
,始终为空。
这是一些例子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 个实体的集合。另一个可接受的解决方案是将标识符直接放在节点中,但我认为如果不在逻辑树中明确包含这些元素,这种语法是不可能的。即...
<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)));
}
我试过使基础 class Identifiers
实现 Freezable
希望它能用于数据和绑定上下文的继承,但没有任何效果(可能是因为它嵌套在另一层内 - 附加的 属性)。
还有几个要点:
- 我希望它适用于任何
UIElement
,而不仅仅是 StackPanel
s
Identifier
不是可视化树的一部分。他们没有也不应该有视觉元素
- 因为这是一个内部库,我宁愿避免要求绑定
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>
我正在尝试将嵌套在附加 属性 内的元素绑定到我的 DataContext
,但问题是附加的 属性 不是逻辑树的一部分,并且因此没有正确设置或绑定到父对象的数据上下文。依赖项 属性,在本例中 Value
,始终为空。
这是一些例子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 个实体的集合。另一个可接受的解决方案是将标识符直接放在节点中,但我认为如果不在逻辑树中明确包含这些元素,这种语法是不可能的。即...
<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)));
}
我试过使基础 class Identifiers
实现 Freezable
希望它能用于数据和绑定上下文的继承,但没有任何效果(可能是因为它嵌套在另一层内 - 附加的 属性)。
还有几个要点:
- 我希望它适用于任何
UIElement
,而不仅仅是StackPanel
s Identifier
不是可视化树的一部分。他们没有也不应该有视觉元素- 因为这是一个内部库,我宁愿避免要求绑定
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>