Clip a 4:3 image in WPF with a circle - c#

I am trying to clip a 4:3 image with a circle within a grid control.
I need the circle clip to reveal the image from the middle in a perfect circle. See below.
alt text http://www.cse.unsw.edu.au/~vjro855/Untitled.png
The circle should dynamically re-size with the image.
I have tried Canvas.Clip and Ellipse+VisualBrush without achieving the correct behavior.
Thanks!

Solved my problem.
The solution was to use converters as part of the Grid.Clip property. I used code from the following site.
http://blogorama.nerdworks.in/entry-CenteringelementsonacanvasinWP.aspx
The challenge I encountered was having to use the EllipseGeometry instead of just Ellipse.
Ellipse uses height and width whilst EllipseGeometry uses radiusx,y and center.
With Ellipse I could have just set height and width to the height of the image to get the clip i required.
Would be a lot simpler if expressions worked with binding ie. {Binding Path=expr}
<Grid>
<Grid.Clip>
<EllipseGeometry>
<EllipseGeometry.RadiusX>
<MultiBinding
Converter="{StaticResource HalfValue1}">
<Binding
ElementName="vemap"
Path="ActualHeight" />
</MultiBinding>
</EllipseGeometry.RadiusX>
<EllipseGeometry.RadiusY>
<MultiBinding
Converter="{StaticResource HalfValue1}">
<Binding
ElementName="vemap"
Path="ActualHeight" />
</MultiBinding>
</EllipseGeometry.RadiusY>
<EllipseGeometry.Center>
<MultiBinding
Converter="{StaticResource HalfValue}">
<Binding
ElementName="vemap"
Path="ActualHeight" />
<Binding
ElementName="vemap"
Path="ActualWidth" />
</MultiBinding>
</EllipseGeometry.Center>
</EllipseGeometry>
</Grid.Clip>
<Image>
</Grid>

Related

Passing incorrect values into MultiValueConverter by MultiBinding

I've been trying to implement a dynamic ToolTip (WPF) for RadioButton (the ToolTip switches, when IsEnabled of the RadioButton changes). I wanted to achieve this with a MultiValueConverter, which would be sort of a general Converter, that accepts 3 values - the IsEnabled value, enabled ToolTip and disabled ToolTip in this exact order.
But sadly I have encountered an issue, that I haven't been able to solve yet. Basically when the code reaches the Convert Method, the Array of values is filled with DependencyProperty.UnsetValue items.
What I managed to find while googling was, that the problem is propably caused by having a wrong DataContext as mentioned here WPF MultiBinding in Convertor fails ==> DependencyProperty.UnsetValue , but I feel like I have tried every combination of RelativeSources and DataContexts, that I could come up with and nothing helped.
Here is the sample code of the View:
<window.Resources>
<local:BooleanToStringConverter x:Key="BooleanToStringConverter"/>
</window.Resources>
<Grid>
<RadioButton x:Name="RadioButton" ToolTipService.ShowOnDisabled="True"
IsEnabled="{Binding IsRadioButtonEnabled}" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Radio">
<RadioButton.ToolTip>
<ToolTip>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource BooleanToStringConverter}">
<Binding ElementName="RadioButton" Path="IsEnabled"/>
<Binding RelativeSource="{RelativeSource AncestorType={x:Type local:MainWindow}}" Path="ViewModel.EnabledToolTip"/>
<Binding RelativeSource="{RelativeSource AncestorType={x:Type local:MainWindow}}" Path="ViewModel.DisabledToolTip"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ToolTip>
</RadioButton.ToolTip>
</RadioButton>
So the result, that I expect from this, is that the correct values will be passed into the Converter (in this case value of IsEnabled and string values of Enabled/Disabled ToolTips).
If anybody has any ideas, I would very much appreciate to hear them :).
Thanks in advance.
I managed to fix this by explicitly setting DataContext on the RadioButton and removing the RelativeSources within the MultiBinding. Though I don't understand why it did not work with the RelativeSources, it works. Here is the code, in case of anyone reading this in the future:
<RadioButton x:Name="RadioButton" ToolTipService.ShowOnDisabled="True"
DataContext="{Binding ViewModel, RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}}"
IsEnabled="{Binding IsRadioButtonEnabled}" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Radio">
<RadioButton.ToolTip>
<ToolTip>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource BooleanToStringConverter}">
<Binding Path="IsRadioButtonEnabled"/>
<Binding Path="EnabledToolTip"/>
<Binding Path="DisabledToolTip"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ToolTip>
</RadioButton.ToolTip>
</RadioButton>

Partly deactivate xaml Styler plugin (at LineBreak MultiBinding cleanup)

I'm using xaml-Styler Plugin on VS2015. So far I didn't had any problems.
Now I have the problem, that the styler removes linebreaks (I use HTML encoded characters).
xaml (simplified)
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}
Min X: {1:F3}; Max X: {2:F3}">
<Binding Path="Area.Name" ... />
<Binding Path="Area.MinX" ... />
<Binding Path="Area.MaxX" ... />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
after Pressing Save, the xaml styler automatically makes this (html character is removed and LineBreak inserted:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}
Min X: {1:F3}; Max X: {2:F3}">
<Binding Path="Area.Name" ... />
<Binding Path="Area.MinX" ... />
<Binding Path="Area.MaxX" ... />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
then the text is displayed at one line.
I'm not happy with using html encoded characters at all. Is there maybe a better (simple) way to format strings with linebreaks in a MultiBinding?
For this simple formatting I don't want to use a MultiValueConverter, because it is only an informative string...
If I could tell xaml styler don't style this part/line I would be happy, but didn't found the possibility or a property in options of xaml styler.
You can use the hex representation of the LineFeed character (char 10) :
to get a line break :
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}
Min X: {1:F3}
Max X: {2:F3}">
<Binding Path="Area.Name" ... />
<Binding Path="Area.MinX" ... />
<Binding Path="Area.MaxX" ... />
</MultiBinding>
</TextBlock.Text>
</TextBlock>

MultiBinding with PriorityBinding workaround

I'm currently working on an app in which borders are displaying objects in a "change-state". The visibility of these borders is controlled using "BorderThickness" and a priority binding (the visibility is set in a converter). Now there's a request to make the thickness of the change-state border configurable (obtained at runtime).
My initial attempt was changing the converter into a multi-binding converter:
<Border.BorderThickness>
<MultiBinding Converter="{StaticResource StringToBorderThickness}">
<PriorityBinding>
<Binding Path="Change1" />
<Binding Path="Change2" />
</PriorityBinding>
<Binding Path="DataContext.Settings.ChangeStateThickness" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" />
</MultiBinding>
</Border.BorderThickness>
This does NOT work because WPF does not support MultiBinding+PriorityBinding at the same time (as it turns out).
Can anyone recommend a workaround? I can't remove the Priority Binding and I can't find a different way to control the border visibility (BorderVisibility also makes the object IN the border invisible)
Thank you.

How to bind to Popup ActualHeight

I have a grid that I want a popup to show in a constant relation to it regardless of the size of both the popup and the grid. I use a converter for it here is the code
< Grid Name=YParamTextBlock>
<TextBlock HorizontalAlignment="Center"/>
<Popup PlacementTarget="{Binding ElementName=YParamTextBlock}} Placement="Center">
<Popup.VerticalOffSet>
<MultiBinding Mode="OneWay" Converter="{StaticResource OffsetConverter} NotifyOnTargetChanged="True">
<Binding Mode="OneWay" ElementName="YParamTextBlock" Path="ActualHeight" NotifyOnTargetUpdated="True"/>
<Binding Mode="OneWay" RelativeSource={RelativeSource Self} Path="ActualHeight" NotifyOnTargetChanged="True"/>
</MultiBinding>
</Popup.VerticalOffset>
</Popup>
<Grid>
The problem is that the actual height is 0.0 for the two controls when they are first created, so I added the NotifyOnTargetChanged in order to fix it.
Now, for some reason the NotifyOnTargetChanged fixed the rebinding for the Grid's ActualHeight, but the Popup is still 0.0. Is there anyway to notify the popup actual height has changed? Or any other solution for this issue?
Actual Height and Width are read-only you cannot bind directly, you can use the solution explained by Kent Boogaart in this Answer
Why the multibinding? VerticalOffset is a double so you just need one binding value.
I don't know what your Converter does, but assuming you want it to take the ActualHeight property of your YParamTextBlock grid and then return a double corresponding to the VerticalOffset you want to give to your popup then the following is probably easier to follow:
<Grid x:Name="YParamTextBlock">
<TextBlock HorizontalAlignment="Center"/>
<Popup PlacementTarget="{Binding ElementName=YParamTextBlock}}
Placement="Center"
VerticalOffset="{Binding ActualHeight, ElementName=YParamTextBlock,
Converter={StaticResource OffsetConverter}}"/>
<Grid>

Drawing Pixels as Custom Shapes

I have a source image, I want to reduce it to pixels using the method at http://notes.ericwillis.com/2009/11/pixelate-an-image-with-csharp/ and draw each pixel as either a filled circle, hollow circle or square (each actual pixel should be about 15px on screen).
The only way I can think of doing this is by creating each pixel as a usercontrol with DependancyProperties for Color and Shape (bound to a path maybe?). A parent UC derived from ItemsControl would create hundreds of these pixel UCs inside itself.
This seems like a performance nightmare though.
EDIT: To give some context, this is for a pixel art generating app. I need to store each 'pixel' in a database with attributes for X, Y and Color.
Is this the best way of achieving this?
Performance is actually very impressive. I used a UserControl (root), with a DependancyProperty for Sprite and an ItemsControl with a multibinding. A MultiValueConverter converts the dots of the art to Path elements, taking the size of the canvas into account:
<ItemsControl>
<ItemsControl.ItemsSource>
<MultiBinding Converter="{StaticResource dotToPixelConverter}">
<Binding Path="Sprite.Beads" ElementName="root"/>
<Binding Path="Sprite.Width" ElementName="root"/>
<Binding Path="Sprite.Height" ElementName="root"/>
<Binding Path="ActualWidth" ElementName="root"/>
<Binding Path="ActualHeight" ElementName="root"/>
</MultiBinding>
</ItemsControl.ItemsSource>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

Categories