Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bind to ActualHeight of Item ItemsControl

I have two separate ItemsControls that appear side by side. The ItemsControls bind to the same ItemsSource, but they display the data differently.

Each item displayed on the left will most likely be smaller than the same item on the right. This causes a problem because the rows will not line up, so I need the item on the left to bind to the item on the right.

ItemsControl        ItemsControl
|Item 1         |Item 1
|Item 2         |Item 2
|Item 3         |
|Item 4         |Item 3

As you can see, Item 2 on the right is larger, so it throws off the alignment. So if I can bind left's Item 2 to right's Item 2's ActualHeight the problem would be solved. How can I do this in XAML?

Edit: To make things more complicated, the ItemsControl on the right needs to scroll right to left, but both ItemsControls need to scroll up and down together. Basically, the left one provides a header of sorts for the items on the right.

like image 206
kevindaub Avatar asked Feb 21 '11 00:02

kevindaub


1 Answers

Following up on Jobi Joy's answer

You can't do a direct OneWayToSource Binding in Xaml for the ReadOnly Dependency Property ActualHeight but there are many workarounds. The answer by Kent Boogaart in this question is my favorite. What is does is that it uses an Attached Behavior that listens to the SizeChanged event of any FrameworkElement and updates two Attached Properties, Width and Height, accordingly.

With a TextBlock for example, ActualHeight can be used to push into a Height property of the ViewModel like

<TextBlock local:ActualSizeBehavior.ObserveActualSize="True"
           local:ActualSizeBehavior.ActualHeight="{Binding Path=Height,
                                                           Mode=OneWayToSource}"
           .../>

Synkronize two ScrollViewers
You can either use a DependencyPropertyDescriptor to listen for changes in the VerticalOffsetProperty property or subscribe to the ScrollChanged event and call ScrollToVerticalOffset. Example

Xaml

<ScrollViewer Name="scrollViewerLeft"
              ScrollChanged="scrollViewerLeft_ScrollChanged">
<ScrollViewer Name="scrollViewerRight"
              ScrollChanged="scrollViewerRight_ScrollChanged">

Code behind event handlers

private void scrollViewerLeft_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
    scrollViewerRight.ScrollToVerticalOffset(scrollViewerLeft.VerticalOffset);
}
private void scrollViewerRight_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
    scrollViewerLeft.ScrollToVerticalOffset(scrollViewerRight.VerticalOffset);
}

ActualSizeBehavior

public static class ActualSizeBehavior
{
    public static readonly DependencyProperty ActualSizeProperty =
        DependencyProperty.RegisterAttached("ActualSize",
                                            typeof(bool),
                                            typeof(ActualSizeBehavior),
                                            new UIPropertyMetadata(false, OnActualSizeChanged));
    public static bool GetActualSize(DependencyObject obj)
    {
        return (bool)obj.GetValue(ActualSizeProperty);
    }
    public static void SetActualSize(DependencyObject obj, bool value)
    {
        obj.SetValue(ActualSizeProperty, value);
    }
    private static void OnActualSizeChanged(DependencyObject dpo,
                                            DependencyPropertyChangedEventArgs e)
    {
        FrameworkElement element = dpo as FrameworkElement;
        if ((bool)e.NewValue == true)
        {
            element.SizeChanged += element_SizeChanged;
        }
        else
        {
            element.SizeChanged -= element_SizeChanged;
        }
    }

    static void element_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        FrameworkElement element = sender as FrameworkElement;
        SetActualWidth(element, element.ActualWidth);
        SetActualHeight(element, element.ActualHeight);
    }

    private static readonly DependencyProperty ActualWidthProperty =
        DependencyProperty.RegisterAttached("ActualWidth", typeof(double), typeof(ActualSizeBehavior));
    public static void SetActualWidth(DependencyObject element, double value)
    {
        element.SetValue(ActualWidthProperty, value);
    }
    public static double GetActualWidth(DependencyObject element)
    {
        return (double)element.GetValue(ActualWidthProperty);
    }

    private static readonly DependencyProperty ActualHeightProperty =
        DependencyProperty.RegisterAttached("ActualHeight", typeof(double), typeof(ActualSizeBehavior));
    public static void SetActualHeight(DependencyObject element, double value)
    {
        element.SetValue(ActualHeightProperty, value);
    }
    public static double GetActualHeight(DependencyObject element)
    {
        return (double)element.GetValue(ActualHeightProperty);
    }
}
like image 58
Fredrik Hedblad Avatar answered Sep 27 '22 17:09

Fredrik Hedblad