当StackPanel父级调整大小时,改变StackPanel的子级



我在一个网格中有一些StackPanel。它们被标签填充(所有标签的高度>可显示空间)。一个可能的XAML是:

<Grid>
  <StackPanel>
    <Label Content="bla" Background="lime" />
    <Label ...>
    ...
  </StackPanel>
</Grid>

每次Grid的大小发生变化,我都需要改变StackPanel的内部内容。我需要隐藏溢出的Label,只显示部分。为了实现这一点,我可以使用以下解决方案:与转换器和创建一个继承自StackPanel的新类。

我想通过使用附加属性创建一种不同的方式。我有以下代码:

//DepProp OverflowVisibility (double), can save height value
public static void Initialized(DependencyObject pObject, DependencyPropertyChangedEventArgs e)
{
  var panel = (pObject as Panel) //the StackPanel in this case
  panel.SizeChanged += panel_updateInnerLayout;
}
static void panel_LayoutUpdated(object sender, EventArgs e)
{
  var parent = sender as Panel;
  if(parent != null)
    foreach(FrameworkElement element in parent.Children)
    {
      var elementPos = element.TransformToAncestor(parent).Transform(new Point(0,0));
      if(element.ActualHeight + elementPos.Y >
        (double)parent.GetValue(OverflowVisibilityProperty))
        element.Visibility = Visibility.Hidden;
      else
        element.Visibility = Visibility.Visible;
    }
}

和在XAML中使用的示例:

<Grid>
  <ItemsControl>
    <ItemsPanel>
      <ItemsPanelTemplate>
        <StackPanel own:OverflowVisibility.OverflowVisibility="{Binding Grid height}" />
      </ItemsPanelTemplate>
    </ItemsPanel>
  </ItemsControl>
</Grid>

每次StackPanel改变它的大小,我可以用panel_updateInnerLayout事件处理程序更新我的标签。当更改StackPanel的大小时,一切都工作正常。

我的问题:StackPanel本身不会提高SizeChanged,因为它的高度比Grid大。我需要一个事件,每次Grid改变其高度时都会引发。

我的问题:是否有任何事件代替SizeChanged,那是每次我改变Grid大小调用?如果没有,是否有附加属性的替代方法来解决我的问题?

我也试图设置StackPanel的高度绑定到ItemsControl的ActualHeight,但它没有提高SizeChanged

不幸的是,您选择了错误的Panel控件来满足您的需求。StackPanel应该只在不需要调整其内容大小时使用,因为它不提供任何子控件调整大小的功能。因此,您应该使用Grid,或任何其他提供调整大小功能的Panel

请参阅MSDN上的面板概述页面,以获得选择合适Panel的进一步帮助。

有两个可能的事件:SizeChangedLayoutUpdatedSizeChanged不工作,因为StackPanel没有调整大小。LayoutUpdated不工作,因为这个事件的sender总是null,我无法找到StackPanel是什么来源。

更多信息请参见:Layout Events - SizeChanged and layoutupupdated。

所以我的方法没有可能的事件可用。

当我寻找解决方案时,我还发现,我使用了术语附加属性也用于附加行为混合行为。这里描述了它们的区别。总结:属性对对象没有任何作用,但它们的存在可以被使用,行为改变对象的行为。Blend行为是微软为Microsoft Blend创建的行为。我的问题中的代码是附加行为

对于附加行为我没有找到解决方案,但对于混合行为我找到了一些。您需要添加一个引用Micosoft.Windows.Interactivity

之后我使用了下面的代码:

public class OverflowVisibilityBehavior : Behavior<VirtualizingStackPanel>
{
  protected override void OnAttached()
  {
    AssociatedObject.LayoutUpdated += AssociatedObject_LayoutUpdated;
    base.OnAttached();
  }
  protected override void OnDetaching()
  {
    AssociatedObject.LayoutUpdated -= AssociatedObject_LayoutUpdated;
  }
  void AssociatedObject_LayoutUpdated(object sender, EventArgs e)
  {
    var parent = AssociatedObject; //that solves the problem: you can get a "sender" information
    //...
    // Instead of property GetValue
    (VisualTreeHelper.GetParent(parent) as ItemsPresenter).ActualHeight
  }
}

仍然存在一些问题:StackPanel的父级必须引发SizeChanged。如果你把StackPanel放到StackPanel放到Grid,你需要修改它。

第二:LayoutUpdated多次修改StackPanel。比我需要的还要多。

最新更新