Reputation: 4662
I have the following XAML:
<sdk:Label Content="{Binding RefreshTextToggle, Converter={StaticResource enumToText}, ConverterParameter=ItemsOfInterest,FallbackValue='Please select items of interest to you'}"
Style="{StaticResource StandardLabel}"
Height="{Binding ElementName=ItemsOfInterest,Path=Height}"/>
<ListBox Name="ItemsOfInterest"
ItemsSource="{Binding Path=ItemsOfInterest}"
Margin="5"
MinHeight="25"
Width="250"
HorizontalAlignment="Left">
The height of the ItemsOfInterest is dynamic pending on how many elements are in it.
Anyone see what I am doing wrong with the height binding? It isn't even close to the same size as the ItemsOfInterst.
Upvotes: 3
Views: 6109
Reputation: 41403
You should bind to ActualHeight, which specifies the height it was arranged at. The Height property allows you to set a fixed height, but doesn't tell you exactly how tall it is when arranged.
Actually, this is a known bug with Silverlight.
You would have to use the SizeChanged event like so:
<UserControl x:Class="SilverlightApplication3.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Content="Add Item" Click="Button_Click" />
<ListBox x:Name="listBox1" Grid.Column="0" Grid.Row="1" VerticalAlignment="Top" SizeChanged="listBox1_SizeChanged" />
<ListBox x:Name="listBox2" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" />
</Grid>
</UserControl>
With a code-behind of:
using System.Windows;
using System.Windows.Controls;
namespace SilverlightApplication3 {
public partial class MainPage : UserControl {
public MainPage() {
InitializeComponent();
}
private int counter;
private void Button_Click(object sender, RoutedEventArgs e) {
this.counter++;
this.listBox1.Items.Add(counter.ToString());
}
private void listBox1_SizeChanged(object sender, SizeChangedEventArgs e) {
this.listBox2.Height = this.listBox1.ActualHeight;
}
}
}
You could probably wrap this up into a nice attached behavior also.
<UserControl x:Class="SilverlightApplication3.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SilverlightApplication3"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Content="Add Item" Click="Button_Click" />
<ListBox x:Name="listBox1" Grid.Column="0" Grid.Row="1" VerticalAlignment="Top" />
<ListBox x:Name="listBox2" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" local:SizeSynchronizationBehavior.HeightElement="{Binding ElementName=listBox1}" />
</Grid>
</UserControl>
With a code-behind of:
using System;
using System.Windows;
using System.Windows.Controls;
namespace SilverlightApplication3 {
public partial class MainPage : UserControl {
public MainPage() {
InitializeComponent();
}
private int counter;
private void Button_Click(object sender, RoutedEventArgs e) {
this.counter++;
this.listBox1.Items.Add(counter.ToString());
}
}
public static class SizeSynchronizationBehavior {
#region Dependency Properties
///////////////////////////////////////////////////////////////////////////////////
// HeightElement
///////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Identifies the <c>HeightElement</c> attached dependency property. This field is read-only.
/// </summary>
/// <value>The identifier for the <c>HeightElement</c> attached dependency property.</value>
public static readonly DependencyProperty HeightElementProperty = DependencyProperty.RegisterAttached("HeightElement",
typeof(FrameworkElement), typeof(SizeSynchronizationBehavior), new PropertyMetadata(null, OnHeightElementPropertyValueChanged));
/// <summary>
/// Gets the value of the <see cref="HeightElementProperty"/> attached property for the specified <see cref="FrameworkElement"/>.
/// </summary>
/// <param name="obj">The object to which the attached property is retrieved.</param>
/// <returns>
/// The value of the <see cref="HeightElementProperty"/> attached property for the the specified <see cref="FrameworkElement"/>.
/// </returns>
public static FrameworkElement GetHeightElement(FrameworkElement obj) {
if (obj == null) throw new ArgumentNullException("obj");
return (FrameworkElement)obj.GetValue(HeightElementProperty);
}
/// <summary>
/// Sets the value of the <see cref="HeightElementProperty"/> attached property to the specified <see cref="FrameworkElement"/>.
/// </summary>
/// <param name="obj">The object to which the attached property is written.</param>
/// <param name="value">
/// The new value of the <see cref="HeightElementProperty"/> attached property to the specified <see cref="FrameworkElement"/>.
/// </param>
public static void SetHeightElement(FrameworkElement obj, FrameworkElement value) {
if (obj == null) throw new ArgumentNullException("obj");
obj.SetValue(HeightElementProperty, value);
}
/// <summary>
/// Called when <see cref="HeightElementProperty"/> is changed.
/// </summary>
/// <param name="d">The dependency object that was changed.</param>
/// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
private static void OnHeightElementPropertyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
FrameworkElement element = d as FrameworkElement;
if (element == null)
return;
SizeChangedEventHandler heightSizeChangedEventHandler = GetSizeChangedEventHandler(element);
if (heightSizeChangedEventHandler == null) {
heightSizeChangedEventHandler = (sender, eventArgs) => {
FrameworkElement he = GetHeightElement(element);
if (he != null)
element.Height = he.ActualHeight;
};
SetSizeChangedEventHandler(element, heightSizeChangedEventHandler);
}
FrameworkElement heightElement = e.OldValue as FrameworkElement;
if (heightElement != null)
heightElement.SizeChanged += heightSizeChangedEventHandler;
heightElement = e.NewValue as FrameworkElement;
if (heightElement != null)
heightElement.SizeChanged += heightSizeChangedEventHandler;
}
///////////////////////////////////////////////////////////////////////////////////
// SizeChangedEventHandler
///////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Identifies the <c>SizeChangedEventHandler</c> attached dependency property. This field is read-only.
/// </summary>
/// <value>The identifier for the <c>SizeChangedEventHandler</c> attached dependency property.</value>
private static readonly DependencyProperty SizeChangedEventHandlerProperty = DependencyProperty.RegisterAttached("SizeChangedEventHandler",
typeof(SizeChangedEventHandler), typeof(SizeSynchronizationBehavior), new PropertyMetadata(null));
/// <summary>
/// Gets the value of the <see cref="SizeChangedEventHandlerProperty"/> attached property for the specified <see cref="FrameworkElement"/>.
/// </summary>
/// <param name="obj">The object to which the attached property is retrieved.</param>
/// <returns>
/// The value of the <see cref="SizeChangedEventHandlerProperty"/> attached property for the the specified <see cref="FrameworkElement"/>.
/// </returns>
private static SizeChangedEventHandler GetSizeChangedEventHandler(FrameworkElement obj) {
if (obj == null) throw new ArgumentNullException("obj");
return (SizeChangedEventHandler)obj.GetValue(SizeChangedEventHandlerProperty);
}
/// <summary>
/// Sets the value of the <see cref="SizeChangedEventHandlerProperty"/> attached property to the specified <see cref="FrameworkElement"/>.
/// </summary>
/// <param name="obj">The object to which the attached property is written.</param>
/// <param name="value">
/// The new value of the <see cref="SizeChangedEventHandlerProperty"/> attached property to the specified <see cref="FrameworkElement"/>.
/// </param>
private static void SetSizeChangedEventHandler(FrameworkElement obj, SizeChangedEventHandler value) {
if (obj == null) throw new ArgumentNullException("obj");
obj.SetValue(SizeChangedEventHandlerProperty, value);
}
#endregion // Dependency Properties
}
}
Upvotes: 5
Reputation: 21178
I have created a simple project which replicates the problem you are experiencing:
On run, the listbox grows, but the associated button does not. I am now working to determine why this fails.
UPDATE
Okay, the reason why this does not work is that Auto does not return any actual value that can be used to determine the height of the listbox by this binding. I tried every other approach to solve this without success. It will be interesting to see the resolution of this problem while just relying on binding.
Upvotes: 0