在自定义面板实现期间,ItemsControl 中附加 属性 的值
Value of Attached Property in ItemsControl, during custom panel implementation
我实现了自定义面板 Shelf
,它根据附加 属性 Shelf.Exact
:
排列子项
class Shelf : Panel
{
public static readonly DependencyProperty ExactProperty = DependencyProperty.RegisterAttached("Exact", typeof(int), typeof(Shelf),
new FrameworkPropertyMetadata(100, new PropertyChangedCallback(OnExactChanged)));
private static void OnExactChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Console.WriteLine(d); // This Callback is added only for debug purposes
}
public static int GetExact(UIElement element)
{
return (int)element.GetValue(ExactProperty);
}
public static void SetExact(UIElement element, int value)
{
element.SetValue(ExactProperty, value);
}
protected override Size MeasureOverride(Size availableSize)
{
Size panelSize = new Size(availableSize.Width, 0);
foreach (UIElement child in InternalChildren)
{
child.Measure(availableSize);
panelSize.Height += child.DesiredSize.Height;
}
return panelSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
foreach (UIElement child in InternalChildren)
{
int exact = Shelf.GetExact(child); // Here I always get 100 which is default value for ExactProperty
child.Arrange(new Rect(new Point(0, exact * 1), child.DesiredSize));
}
return finalSize;
}
}
<ItemsControl ItemsSource="{Binding Path=Packs}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:Shelf />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock local:Shelf.Exact="{Binding Path=Number}" Text="{Binding Path=Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
就像我在上面的代码注释中提到的,我总是得到 Shelf.DependencyProperty
的默认值。我不明白这是为什么?
第一个想法是绑定搞砸了。所以我添加 PropertyChangedCallback
并检查更改的值是否被触发 → 回调被调用并且 d.NewValue
正常但仍然在 ArrangeOverride()
中获得默认值。接下来我完全摆脱绑定,所以我硬编码 local:Shelf.Exact="123"
→ 我仍然得到默认值。
而且当我直接使用 Shelf
时它完美地工作:
<local:Shelf Grid.Column="1">
<TextBlock local:Shelf.Exact="223">Test</TextBlock>
<TextBlock local:Shelf.Exact="332">Test</TextBlock>
<TextBlock local:Shelf.Exact="443">Test</TextBlock>
</local:Shelf>
DataTemplate中的TextBlock不是ItemsPanel测量排列的元素。
您必须在 ItemContainerStyle 中的项目容器(即 ContentPresenter)上设置附加 属性:
<ItemsControl ItemsSource="{Binding Packs}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:Shelf/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="local:Shelf.Exact" Value="{Binding Number}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
我实现了自定义面板 Shelf
,它根据附加 属性 Shelf.Exact
:
class Shelf : Panel
{
public static readonly DependencyProperty ExactProperty = DependencyProperty.RegisterAttached("Exact", typeof(int), typeof(Shelf),
new FrameworkPropertyMetadata(100, new PropertyChangedCallback(OnExactChanged)));
private static void OnExactChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Console.WriteLine(d); // This Callback is added only for debug purposes
}
public static int GetExact(UIElement element)
{
return (int)element.GetValue(ExactProperty);
}
public static void SetExact(UIElement element, int value)
{
element.SetValue(ExactProperty, value);
}
protected override Size MeasureOverride(Size availableSize)
{
Size panelSize = new Size(availableSize.Width, 0);
foreach (UIElement child in InternalChildren)
{
child.Measure(availableSize);
panelSize.Height += child.DesiredSize.Height;
}
return panelSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
foreach (UIElement child in InternalChildren)
{
int exact = Shelf.GetExact(child); // Here I always get 100 which is default value for ExactProperty
child.Arrange(new Rect(new Point(0, exact * 1), child.DesiredSize));
}
return finalSize;
}
}
<ItemsControl ItemsSource="{Binding Path=Packs}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:Shelf />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock local:Shelf.Exact="{Binding Path=Number}" Text="{Binding Path=Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
就像我在上面的代码注释中提到的,我总是得到 Shelf.DependencyProperty
的默认值。我不明白这是为什么?
第一个想法是绑定搞砸了。所以我添加 PropertyChangedCallback
并检查更改的值是否被触发 → 回调被调用并且 d.NewValue
正常但仍然在 ArrangeOverride()
中获得默认值。接下来我完全摆脱绑定,所以我硬编码 local:Shelf.Exact="123"
→ 我仍然得到默认值。
而且当我直接使用 Shelf
时它完美地工作:
<local:Shelf Grid.Column="1">
<TextBlock local:Shelf.Exact="223">Test</TextBlock>
<TextBlock local:Shelf.Exact="332">Test</TextBlock>
<TextBlock local:Shelf.Exact="443">Test</TextBlock>
</local:Shelf>
DataTemplate中的TextBlock不是ItemsPanel测量排列的元素。
您必须在 ItemContainerStyle 中的项目容器(即 ContentPresenter)上设置附加 属性:
<ItemsControl ItemsSource="{Binding Packs}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:Shelf/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="local:Shelf.Exact" Value="{Binding Number}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>