I have a complex "Dot" in WPF which I need to customize the diameter.
The control code sample:
<UserControl>
<Canvas>
<Canvas.RenderTransform>
<TranslateTransform X="-6" Y="-6"/>
</Canvas.RenderTransform>
<Ellipse Width="12" Height="12" x:Name="BigCircle" Fill="Red"/>
<Ellipse Width="8" Height="8" x:Name="MediumCircle" Fill="Green" Canvas.Left="2" Canvas.Top="2"/>
<Ellipse Width="4" Height="4" x:Name="SmallCircle" Fill="Blue" Canvas.Left="4" Canvas.Top="4" />
</Canvas>
</UserControl>
What I want to achieve:
<UserControl>
<UserControl.Resources>
<sys:Double x:Key="dd">120</sys:Double>
</UserControl.Resources>
<Canvas>
<Canvas.RenderTransform>
<TranslateTransform X="-dd/2" Y="-dd/2"/>
</Canvas.RenderTransform>
<Ellipse Width="{DynamicResource ResourceKey=dd}" Height="{DynamicResource ResourceKey=dd}" x:Name="BigCircle" Fill="Red"/>
<Ellipse Width="dd*2/3" Height="dd*2/3" x:Name="MediumCircle" Fill="Green" Canvas.Left="dd/6" Canvas.Top="dd/6"/>
<Ellipse Width="dd/3" Height="dd/3" x:Name="SmallCircle" Fill="Blue" Canvas.Left="dd/3" Canvas.Top="dd/3" />
</Canvas>
</UserControl>
every time I change "dd" then I want that my circles proportionally changes.
Using Converters
[ValueConversion(typeof(double), typeof(double))]
public class LargeToMediumConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((double)value * 2) / 3;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
/* XAML */
<UserControl.Resources>开发者_StackOverflow中文版
<sys:Double x:Key="DotDiameter">12</sys:Double>
</UserControl.Resources>
...
<Ellipse Width="{Binding ElementName=DotDiameter}" Height="{Binding ElementName=DotDiameter}" x:Name="LargeCircle" ...
...
so this does not work....
Wow! You all are working way too hard. WPF can do your layout for you, and easily too.
This will do exactly what you are looking for with no converters or other code of any kind:
<UserControl>
<UserControl.Resources>
<sys:Double x:Key="dd">120</sys:Double>
</UserControl.Resources>
<Canvas>
<Grid Width="2000000" Height="2000000" RenderTransform="1 0 0 1 -1000000 -1000000">
<Viewbox Width="{DynamicResource dd}" Height="{DynamicResource dd}" VerticalAlignment="Center" HorizontalAlignment="Center">
<Grid Width="12" Height="12">
<Ellipse Width="12" Height="12" Fill="Red" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Ellipse Width="8" Height="8" Fill="Green" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Ellipse Width="4" Height="4" Fill="Blue" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Viewbox>
</Grid>
</Canvas>
</UserControl>
This is only one of many ways to do it.
How it works
- The inner Grid and its three Ellipses are all in a fixed size and position.
- The Viewbox resizes the bulls-eye to the desired size.
- The outer Grid centers the bulls-eye at (0,0). This is a convenient idiom for centering: Create a grid 2-million square, center the object in the grid, and then transform it by 1-million to the center.
- The Canvas prevents clipping.
Note that the bulls-eye can also easily be done with a Drawing: Just replace the Viewbox with a Rectangle whose Fill brush is the drawing of the bulls-eye. Using a Drawing would be more efficient but less flexible (no ability to animate the ellipses, etc).
Converters have their place, but it is usually best to let WPF do the layout for you, especially in simple cases like this. Even in complex cases I recommend people write a Panel that does their custom layout instead of using converters.
A Converter
is an option. The expression converter in my WPF converters library will allow you to calculate values based on an expression:
<sys:Double x:Key="OuterWidth">120</sys:Double>
...
<Ellipse Width="{StaticResource OuterWidth}" .../>
<Ellipse Width="{Binding Source={StaticResource OuterWidth}, Converter={kb:ExpressionConverter 2/3*{0}}}" .../>
<Ellipse Width="{Binding Source={StaticResource OuterWidth}, Converter={kb:ExpressionConverter 1/3*{0}}}" .../>
Another option, if you're doing MVVM, is to just expose separate properties from your view model - one for the width of each ellipse. Then bind to them in your view:
<Ellipse Width="{Binding LargeWidth}" .../>
<Ellipse Width="{Binding MediumWidth}" .../>
<Ellipse Width="{Binding SmallWidth}" .../>
You need a BindingConverter
. Check out the following tutorial for more details.
You cant bind to mathematical expressions.
精彩评论