1

I have some StackPanels in a Grid. They are filled with Labels (height of all labels > displayable space). A possible XAML would be:

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

Every time the size of the Grid changes, I need to change the inner content of the StackPanel. I need to hide the overflowing Label that is only shown partly. To achieve this, I can use following solutions: with a Converter and make a new class that is inherited from StackPanel.

I want to create a different way by using an attached property. I have following code:

//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;
    }
}

And an example for usage in XAML:

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

Every time the StackPanel changes it's size, I can update my labels with the panel_updateInnerLayout event handler. When the size of StackPanel is changed, everything is working fine.

My Problem: The StackPanel itself doesn't raise SizeChanged because it has a bigger height than the Grid. I need an event that raises every time the Grid changes its height.

My Question: Is there any event instead of SizeChanged, that is called every time I change the Grid size? If not, is there an alternative way with an attached property to solve my problem?

I also tried to set a binding of the height of the StackPanel to ItemsControl ActualHeight but it does not raise the SizeChanged.

Community
  • 1
  • 1
fedab
  • 978
  • 11
  • 38
  • try to achieve it with setting Margins and Creating dynamic sized Grid rows and columns. – USER_NAME Aug 22 '14 at 09:18
  • What effect are to trying to achieve? – Emond Aug 22 '14 at 09:21
  • @ErnodeWeerd Hide the overflowing item (here Label) that would only displayed partly in the `StackPanel`. – fedab Aug 22 '14 at 09:26
  • @ErnodeWeerd Thanks for the "marked as duplicate" link, this solved the problem by creating a new class. I'm still curious if it would be possible with that attached property because the work i showed in my question is very close to the desired solution. Should i ask a new question or edit it? – fedab Aug 22 '14 at 12:13
  • @fedab - first try to write the attached property and if you run into a specific problem ask a new, specific question. Do not ask whether it is possible or not, try first. This way you are not asking others to do your work, you are asking answerable questions and learning way more than you would otherwise. – Emond Aug 22 '14 at 12:37
  • @ErnodeWeerd When i asked, i already had the attached property written and a specific problem with it (no available event for problem). I also tried many events and different properties to raise `SizeChanged`. I edited my question. Maybe now it's better? – fedab Aug 25 '14 at 08:35

2 Answers2

1

Unfortunately, you have chosen the wrong Panel control for your requirements. The StackPanel should only be used when the resizing of its contents is not required, because it doesn't provide any child control resizing abilities. Therefore, you should use a Grid, or any other Panel that provides resizing abilities. Please refer to the Panels Overview page on MSDN for further help with choosing the appropriate Panel.

Sheridan
  • 68,826
  • 24
  • 143
  • 183
0

There are 2 possible events: SizeChanged and LayoutUpdated. SizeChanged doesn't work because the StackPanel is not resized. LayoutUpdated does not work, because the sender of this event is always null and i can not locate what StackPanel was the source.

For more see: Layout Events - SizeChanged and LayoutUpdated.

So there are no possible event available for my approach.

While I searched for a solution, I also found out, that I used the term attached property also for attached behavior and blend behavior. The difference is described here. Summary: properties do nothing with the object but their presence can be used, behaviours change the object behavior. Blend behaviors are behaviors that Microsoft created for Microsoft Blend. The code in my question is attached behavior.

For attached behaviors I didn't found a solution, but for Blend behaviors i found some. You need to add a reference Micosoft.Windows.Interactivity.

After that i used this code:

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
  }
}

Some problems left: The parent of the StackPanel must raise SizeChanged. If you put a StackPanel in a StackPanel in a Grid, you need modify it.

Second: LayoutUpdated changes the StackPanel several times. More times than i need.

fedab
  • 978
  • 11
  • 38