Cannot set CornerRadius value from static resource

3.6k views Asked by At

I have defined a static resource:

<UserControl x:Class="MyProject.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:sys="clr-namespace:System;assembly=mscorlib" 
   mc:Ignorable="d" 
   Width="255" 
   Height="300">

   <UserControl.Resources>
      <sys:Double x:Key="CornerRadiusValue">5</sys:Double>
   </UserControl.Resources>
...

Later on in XAML file, I am trying to use that value when setting top left corner radius for a border:

<Border 
   Width="40"
   Height="30"
   BorderThickness="1,1,0,0" 
   BorderBrush="Red">
      <Border.CornerRadius>
         <CornerRadius TopLeft="{StaticResource CornerRadiusValue}" />
      </Border.CornerRadius>
</Border>

In design time, everything works fine and changing the value for CornerRadiusValue static resource changes the corner radius on a border. However, when I want to run this, I get an XamlParseException exception with the message:

Cannot set read-only property `System.Windows.CornerRadius.TopLeft'.

What am I doing wrong? How do I make it work? Thanks.

3

There are 3 answers

0
brunnerh On BEST ANSWER

MSDN:

You can set this value in XAML, but only as part of the attribute syntax for properties that take a CornerRadius, or as initialization text of a CornerRadius object element. See XAML sections and Remarks sections of CornerRadius.

You could try to bind the whole CornerRadius property and use a converter to get all the resources and create a CornerRadius instance from them using the constructor.

e.g. using only one value:

<Border Name="bd" BorderBrush="Red" BorderThickness="1">
    <Border.Resources>
        <sys:Double x:Key="CR_TopLeft">5</sys:Double>
    </Border.Resources>
    <Border.CornerRadius>
        <Binding ElementName="bd">
            <Binding.Converter>
                <vc:CornerRadiusConverter />
            </Binding.Converter>
        </Binding>
    </Border.CornerRadius>
    <Button>!</Button>
</Border>
public class CornerRadiusConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var resourceSource = (FrameworkElement)value;
        var topLeft = (double)resourceSource.Resources["CR_TopLeft"];
        return new CornerRadius(topLeft, 0, 0, 0);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

You could propbably make this more generic by searching for the resources going up the tree and not directly targeting the object on which the resources are defined.

(This is a Silverlight-only problem, in WPF your code works just fine, if you have a Silverlight question please avoid the WPF tag unless the problem actually exists in WPF)

3
Rachel On

I believe CornerRadius properties are not DependencyProperties, so they cannot be set through a binding.

The two alternatives I can think of is to use a MultiConverter which accepts the parameters of the Border object, and desired CornerRadius, or to create a custom DependencyProperty for the CornerRadius. Both methods would require you to set the value in code-behind.

1
Dirk Schiller On
<sys:Double x:Key="ScrollbarHandleCrValue">3</sys:Double>
<CornerRadius x:Key="ScrollbarHandleCornerRadius" 
   TopLeft="{StaticResource ScrollbarHandleCrValue}" 
   TopRight="{StaticResource ScrollbarHandleCrValue}" 
   BottomRight="{StaticResource ScrollbarHandleCrValue}" 
   BottomLeft="{StaticResource ScrollbarHandleCrValue}" />

...
<Border Name="Border"
   CornerRadius="{StaticResource ScrollbarHandleCornerRadius}" 
   Background="{StaticResource ScrollbarHandleColor}"
   BorderBrush="Transparent"
   BorderThickness="1" />
...