将附加行为添加到ItemsPanelTemplate

时间:2013-12-01 06:09:59

标签: wpf silverlight xaml mvvm attached-properties

我正在尝试向我的ItemsPanelTemplate添加行为,其中所有项目都已折叠,但顶部的项目除外,因此我指定了一个具有自定义附加行为的StackPanel。

<ItemsControl ItemsSource="{Binding ViewModels}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel my:ElementUtilities.CollapseAllButLast="True"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

问题是当在我的行为中调用LayoutUpdated事件处理程序时,发送方始终为null。这是为什么?

public static class ElementUtilities
{
    public static readonly DependencyProperty CollapseAllButLastProperty = DependencyProperty.RegisterAttached
        ("CollapseAllButLast", typeof(bool), typeof(ElementUtilities), new PropertyMetadata(false, CollapseAllButLastChanged));

    static void CollapseAllButLastChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        StackPanel sp = o as StackPanel;
        if (sp != null)
        {
            if (e.NewValue != null && (bool)e.NewValue)
                sp.LayoutUpdated += sp_LayoutUpdated;
            else
                sp.LayoutUpdated -= sp_LayoutUpdated;
        }
        else
            throw new InvalidOperationException("The attached CollapseAllButLast property can only be applied to StackPanel instances.");
    }

    public static bool GetCollapseAllButLast(StackPanel stackPanel)
    {
        if (stackPanel == null)
            throw new ArgumentNullException("stackPanel");
        return (bool)stackPanel.GetValue(CollapseAllButLastProperty);
    }

    public static void SetCollapseAllButLast(StackPanel stackPanel, bool collapseAllButLast)
    {
        if (stackPanel == null)
            throw new ArgumentNullException("stackPanel");
        stackPanel.SetValue(CollapseAllButLastProperty, collapseAllButLast);
    }

    static void sp_LayoutUpdated(object sender, EventArgs e)
    {
        // Collapse all but last element
        StackPanel sp = (StackPanel)sender;     // This is always null
        for (int i = 0; i < sp.Children.Count - 1; i++)
        {
            UIElement l = sp.Children[i];
            l.Visibility = Visibility.Collapsed;
        }
        sp.Children[sp.Children.Count - 1].Visibility = Visibility.Visible;
    }
}

1 个答案:

答案 0 :(得分:2)

根据LayoutUpdated事件的MSDN文档 -

  

处理LayoutUpdated时,请不要依赖发件人值。 :用于   LayoutUpdated,sender始终为null ,无论处理程序在何处   被附上。这是为了防止处理程序分配任何含义   发件人,例如暗示它是引发的特定元素   事件出自视觉树。

相反,您可以挂钩loaded event -

if (e.NewValue != null && (bool)e.NewValue)
   sp.Loaded += sp_Loaded;
else
   sp.Loaded -= sp_Loaded;