You can solve this without code behind by creating a proxy control. People often use this approach to get correctly updating ActualWidth and ActualHeight properties they can bind to as in the answer to this question.
In your case, you would want to bind the element of the proxy control to some element which is stretching to the full window size. When the width or height of the bound element changes you can then set the value of two properties on your proxy control to be the calculated proportional height and width. You can then just bind to these proportional sizes for the width and height of your user control.
For example:
public class ProportionalSizeHelper : FrameworkElement, INotifyPropertyChanged
{
private double _proportionalWidth = 0;
private double _proportionalHeight = 0;
public event PropertyChangedEventHandler PropertyChanged;
public FrameworkElement Element
{
get { return (FrameworkElement)GetValue(ElementProperty); }
set { SetValue(ElementProperty, value); }
}
public double ProportionalHeight
{
get{ return _proportionalHeight; }
}
public double ProportionalWidth
{
get { return _proportionalWidth; }
}
public static readonly DependencyProperty ElementProperty =
DependencyProperty.Register("Element", typeof(FrameworkElement), typeof(ProportionalSizeHelper),
new PropertyMetadata(null,OnElementPropertyChanged));
private static void OnElementPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((ProportionalSizeHelper)d).OnElementChanged(e);
}
private void OnElementChanged(DependencyPropertyChangedEventArgs e)
{
FrameworkElement oldElement = (FrameworkElement)e.OldValue;
FrameworkElement newElement = (FrameworkElement)e.NewValue;
if (newElement != null)
{
newElement.SizeChanged += new SizeChangedEventHandler(Element_SizeChanged);
}
else
{
_proportionalHeight = 0;
_proportionalWidth = 0;
}
if (oldElement != null)
{
oldElement.SizeChanged -= new SizeChangedEventHandler(Element_SizeChanged);
}
NotifyPropChange();
}
private void Element_SizeChanged(object sender, SizeChangedEventArgs e)
{
// This can be whatever calculation you need
double factor = Math.Min(Element.ActualWidth/1024, Element.ActualHeight/768);
_proportionalHeight = 100*factor;
_proportionalWidth = 300*factor;
NotifyPropChange();
}
private void NotifyPropChange()
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("ProportionalWidth".NonNls()));
PropertyChanged(this, new PropertyChangedEventArgs("ProportionalHeight".NonNls()));
}
}
}
Then in the xaml, with UserControl changed to whatever you need:
<Grid x:Name="LayoutRoot">
<Grid.Resources>
<c:ProportionalSizeHelper Element="{Binding ElementName=LayoutRoot}" x:Name="proxy" />
</Grid.Resources>
<UserControl Width="{Binding ProportionalWidth, ElementName=proxy}" Height={Binding ProportionalHeight, ElementName=proxy} />
</Grid>