【问题标题】:Change children of StackPanel when StackPanel parent is resizing当 StackPanel 父级调整大小时更改 StackPanel 的子级
【发布时间】:2014-08-22 09:13:32
【问题描述】:

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

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

每次Grid的大小改变时,我都需要改变StackPanel的内部内容。我需要隐藏仅部分显示的溢出Label。为此,我可以使用以下解决方案:with a Convertermake a new class that is inherited from 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 改变其高度时引发的事件。

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

我还尝试将StackPanel 的高度绑定到ItemsControl ActualHeight 但它不会提高SizeChanged

【问题讨论】:

  • 尝试通过设置边距和创建动态大小的网格行和列来实现它。
  • 想要达到什么效果?
  • @ErnodeWeerd 隐藏仅在StackPanel 中部分显示的溢出项(此处为标签)。
  • @ErnodeWeerd 感谢“标记为重复”链接,这通过创建一个新类解决了问题。我仍然很好奇是否可以使用该附加属性,因为我在问题中展示的工作非常接近所需的解决方案。我应该问一个新问题还是编辑它?
  • @fedab - 首先尝试编写附加属性,如果遇到特定问题,请提出新的特定问题。不要问能不能,先试试。这样一来,您就不会要求其他人做您的工作,而是在提出可回答的问题并以比其他方式更多的学习方式。

标签: c# wpf xaml


【解决方案1】:

很遗憾,您选择了错误的Panel 控件来满足您的要求。 StackPanel 仅应在不需要需要调整其内容大小时使用,因为它不提供任何子控件调整大小的能力。因此,您应该使用Grid 或任何其他提供调整大小功能的Panel。请参阅 MSDN 上的 Panels Overview 页面,以获取有关选择合适的 Panel 的更多帮助。

【讨论】:

    【解决方案2】:

    有 2 个可能的事件:SizeChangedLayoutUpdatedSizeChanged 不起作用,因为 StackPanel 未调整大小。 LayoutUpdated 不起作用,因为此事件的 sender 始终是 null,我无法找到 StackPanel 的来源。

    更多信息请见:Layout Events - SizeChanged and LayoutUpdated

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

    当我搜索解决方案时,我还发现,我也使用术语 attached property 来表示 attached behaviorblend behavior .差异描述为here。摘要:属性对对象没有任何作用,但可以使用它们的存在,行为改变对象的行为。 Blend 行为是 Microsoft 为 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。比我需要的次数多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-29
      • 2011-03-06
      • 1970-01-01
      • 1970-01-01
      • 2014-07-14
      • 2023-04-01
      • 2018-01-06
      相关资源
      最近更新 更多