Reputation: 2786
I want to bind the height of a control the sum of two other heights, so the UI looks nice various screen sizes.
<GridView
AutomationProperties.AutomationId="ItemDetails"
ItemsSource="{Binding data}"
IsSwipeEnabled="False"
SelectionMode="None" Height="{Binding Height, (ElementName=item - ElementName=itemTitle)}" >
<GridView.ItemTemplate>
<DataTemplate>
<dll:TaskItemControl/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
The above XAML is invalid, but it demonstrates what I want to do. I have two elements, item
and itemTitle
. item
is a ScrollView
that gets set to the height of the screen and I want the GridView
to be the same height as the ScrollView
minus the height of the itemTitle
.
Is there a way to do this in XAML?
Note: The reasons for doing this are beyond the scope of this question. So please don't comment about restricting the height of a control within a ScrollView
.
Upvotes: 0
Views: 247
Reputation: 39006
This can be easily done in code behind by subscribing the SizeChanged
events of the two elements and update the Height
of the GridView
whenever the handlers are called.
But you want a pure XAML solution, and this is where Behaviors come into play.
Use a Behavior.
First you need to add Blend SDK reference to your project.
Then you need to create a new class that implements IBehavior
. This class needs three dependency properties
just to reference the GridView
, the item
and the itemTitle
. So you can subscribe to their SizeChanged
events and calulate the Height
accordingly.
I choose to attach this behavior to a top level Panel
(most likely your LayoutRoot Grid
) because I want to ensure that all the elements under it are rendered properly inside its Loaded
event handler.
The full Behavior class would look something like this -
public class HeightBehavior : DependencyObject, IBehavior
{
public GridView GridView
{
get { return (GridView)GetValue(GridViewProperty); }
set { SetValue(GridViewProperty, value); }
}
public static readonly DependencyProperty GridViewProperty =
DependencyProperty.Register("GridView", typeof(GridView), typeof(HeightBehavior), new PropertyMetadata(null));
public FrameworkElement FirstItem
{
get { return (FrameworkElement)GetValue(FirstItemProperty); }
set { SetValue(FirstItemProperty, value); }
}
public static readonly DependencyProperty FirstItemProperty =
DependencyProperty.Register("FirstItem", typeof(FrameworkElement), typeof(HeightBehavior), new PropertyMetadata(null));
public FrameworkElement SecondItem
{
get { return (FrameworkElement)GetValue(SecondItemProperty); }
set { SetValue(SecondItemProperty, value); }
}
public static readonly DependencyProperty SecondItemProperty =
DependencyProperty.Register("SecondItem", typeof(FrameworkElement), typeof(HeightBehavior), new PropertyMetadata(null));
public DependencyObject AssociatedObject { get; set; }
public void Attach(DependencyObject associatedObject)
{
this.AssociatedObject = associatedObject;
var control = (Panel)this.AssociatedObject;
control.Loaded += AssociatedObject_Loaded;
}
private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
{
this.FirstItem.SizeChanged += FirstItem_SizeChanged;
this.SecondItem.SizeChanged += SecondItem_SizeChanged;
// force to re-calculate the Height
this.FirstItem.Width += 0.5;
}
private void FirstItem_SizeChanged(object sender, SizeChangedEventArgs e)
{
this.SetAssociatedObjectsHeight();
}
private void SecondItem_SizeChanged(object sender, SizeChangedEventArgs e)
{
this.SetAssociatedObjectsHeight();
}
private void SetAssociatedObjectsHeight()
{
this.GridView.Height = this.FirstItem.ActualHeight - this.SecondItem.ActualHeight;
}
public void Detach()
{
this.FirstItem.SizeChanged -= FirstItem_SizeChanged;
this.SecondItem.SizeChanged -= SecondItem_SizeChanged;
var control = (Panel)this.AssociatedObject;
control.Loaded -= AssociatedObject_Loaded;
}
}
Then in my XAML, I attach it to my top level Grid
, like this.
<Grid x:Name="LayoutRoot">
<Interactivity:Interaction.Behaviors>
<local:HeightBehavior GridView="{Binding ElementName=itemGridView}" FirstItem="{Binding ElementName=item}" SecondItem="{Binding ElementName=itemTitle}"/>
</Interactivity:Interaction.Behaviors>
Hope this helps.
Upvotes: 3