Help with WPF Binding - wpf

I need to bind the custom dependency property to the Image elements inside a control.
Now the Label's Foreground binds very well to TextForeground, but not the GeometryDrawing inside the Image (the Image remains Transparent).
What is wrong?
<UserControl x:Class="MyStopControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" Height="12" Width="24">
<Canvas >
<Image x:Name="Dot" Canvas.Left="0" Canvas.Top="0">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Brush="{Binding RelativeSource={x:Static RelativeSource.Self},Path=TextForeground}" Thickness="2" x:Name="BigCircleThickness"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<GeometryGroup>
<EllipseGeometry x:Name="BigCircle" Center="0,0" RadiusX="7" RadiusY="7"/>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Brush="{Binding RelativeSource={x:Static RelativeSource.Self},Path=TextForeground}" Thickness="1"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<GeometryGroup>
<EllipseGeometry x:Name="MediumCircle" Center="0,0" RadiusX="4" RadiusY="4"/>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="{Binding RelativeSource={x:Static RelativeSource.Self},Path=TextForeground}">
<GeometryDrawing.Geometry>
<GeometryGroup>
<EllipseGeometry x:Name="SmallCircle" Center="0,0" RadiusX="2" RadiusY="2"/>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
<Border x:Name="StopShadow"
Background="{Binding ElementName=TextBackground}"
LayoutTransform="{Binding ElementName=StopText, Path=LayoutTransform}">
<Label x:Name="StopLabel"
Content="Bla bla some text"
Foreground="{Binding ElementName=TextForeground}" />
</Border>
</Canvas>
</UserControl>

GeometryDrawing does not have a TextForeground property. You are referencing Self, which would be the GeometryDrawing. Change your RelativeSource if you are trying to grab the TextForeground from a different Control.
<GeometryDrawing.Pen>
<Pen Brush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=TextForeground}" Thickness="1"/>
</GeometryDrawing.Pen>

<UserControl x:Name="MyStopControl" >
...
<Pen Brush="{Binding ElementName=MyStopControl, Path=TextForeground}"/>
...
</UserControl>

Related

How to combine two different styles into one in xaml?

In my xaml page, I have one style and one drawingbrush which are given below -
<Style x:Key="ICON_STYLE" TargetType="Rectangle">
<Setter Property="Fill">
<Setter.Value>
<DrawingBrush Viewbox="0,0,39.125,39.125" ViewboxUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=uiEntityViews:BaseView}, Path=MeSiteColor}" Geometry="F1M19.5625,0.999954C29.8144,0.999954 38.125,9.31053 38.125,19.5625 38.125,29.8142 29.8143,38.1249 19.5625,38.1249 9.31073,38.1249 1,29.8142 1,19.5625 1,9.31053 9.31064,0.999954 19.5625,0.999954z">
<GeometryDrawing.Pen>
<Pen DashCap="Square" EndLineCap="Flat" LineJoin="Round" MiterLimit="10" StartLineCap="Flat" Thickness="2">
<Pen.Brush>
<LinearGradientBrush EndPoint="0.849422,0.849423" StartPoint="0.150577,0.150578">
<GradientStop Color="#FF657783" Offset="0"/>
<GradientStop Color="White" Offset="0.146"/>
<GradientStop Color="#FF2C4758" Offset="1"/>
</LinearGradientBrush>
</Pen.Brush>
<Pen.DashStyle>
<DashStyle/>
</Pen.DashStyle>
</Pen>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Setter.Value>
</Setter>
</Style>
<DrawingBrush x:Key="ICON_BRUSH">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="Gray" Geometry="F1 M0,25 L25,50, 50,25 25,0z">
<GeometryDrawing.Pen>
<Pen DashCap="Triangle" EndLineCap="Flat" LineJoin="Bevel" MiterLimit="10" StartLineCap="Flat" Thickness="5">
<Pen.Brush>
<LinearGradientBrush>
<GradientStop Color="Red" Offset="0"/>
<GradientStop Color="Green" Offset="1"/>
</LinearGradientBrush>
</Pen.Brush>
<Pen.DashStyle>
<DashStyle/>
</Pen.DashStyle>
</Pen>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
How do I combine these two into one style. I have tried the following but it did not work.
<Style x:Key="COMBINED_NODE_ICON" TargetType="Rectangle" BasedOn="{StaticResource ICON_STYLE}">
<Setter Property="Fill">
<Setter.Value>
<DrawingBrush TileMode="None">
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Transform>
<TranslateTransform X="0.2" Y="0.2" />
</DrawingGroup.Transform>
<GeometryDrawing Brush="{StaticResource ICON_BRUSH}">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,1,1" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Setter.Value>
</Setter>
Any help will be highly appreciated. Thanks.
This should work (dkozl plus BasedOn):
<Style x:Key="COMBINED_NODE_ICON"
TargetType="Rectangle"
BasedOn="{StaticResource ICON_STYLE}">
<Setter Property="Fill"
Value="{StaticResource ICON_BRUSH}" />
</Style>
The BasedOn part can be omitted (pure dkozl) as long as your base style (ICON_STYLE) contains nothing but the Fill Setter, since the Fill property is overridden inside style COMBINED_NODE_ICON.
But also your code is working, if you add the last line of
<DrawingBrush x:Key="ICON_BRUSH">
...
</DrawingBrush>
and the last line of
<Style x:Key="COMBINED_NODE_ICON" TargetType="Rectangle" BasedOn="{StaticResource ICON_STYLE}">
...
</Style>

DrawingBrush always rendered on CPU (not GPU)?

I'm struggling with some WPF performance issues. The Ants profiler and dotTrace both show that all the time is deep in the WPF internals. I have a number of DrawingBrush objects presently in use. The old WpfPerf.exe shows that my DrawingBrush objects are being rendered on the CPU instead of the GPU. Is there something I can do to change that? Below is an example of one. Why does it render CPU-side?
<DataTemplate DataType="mapViewModel:ObstacleVM" x:Key="ObstacleShapeTemplate">
<Path Stroke="{DynamicResource Mobius.UI.Resources.Colors.ObstacleShapeOutlineBrush}" StrokeThickness="{Binding WorldAndScreen.MetersPerPixel, Converter={StaticResource Multiplier}, ConverterParameter=1}" StrokeLineJoin="Bevel" StrokeEndLineCap="Square" StrokeStartLineCap="Flat">
<Path.Fill>
<DrawingBrush Stretch="Uniform" ViewportUnits="Absolute" TileMode="Tile">
<DrawingBrush.Transform>
<ScaleTransform ScaleY="{Binding WorldAndScreen.MetersPerPixel, Converter={StaticResource Multiplier}, ConverterParameter=5}" />
</DrawingBrush.Transform>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="{DynamicResource Mobius.UI.Resources.Colors.ObstacleShapeFillBrush}">
<GeometryDrawing.Geometry>
<GeometryGroup FillRule="Nonzero">
<PathGeometry>
<PathFigure StartPoint="0,0">
<LineSegment Point="1,0" />
<LineSegment Point="1,1" />
<LineSegment Point="0,1" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="{DynamicResource Mobius.UI.Resources.Colors.ObstacleShapeOutlineBrush}">
<GeometryDrawing.Geometry>
<GeometryGroup FillRule="Nonzero">
<PathGeometry>
<PathFigure StartPoint="0,0">
<LineSegment Point="0,.33" />
<LineSegment Point="1,.33" />
<LineSegment Point="1,0" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Path.Fill>
<Path.Data>
<PathGeometry FillRule="Nonzero" Figures="{Binding Figures, FallbackValue={StaticResource DefaultFigures}}" />
</Path.Data>
</Path>
</DataTemplate>
After reading around further, I found some sources suggesting the use of VisualBrish instead. Indeed, I tried this and it seems to fix it (again, according to WpfPerf.exe).
<DataTemplate DataType="mapViewModel:ObstacleVM" x:Key="ObstacleShapeTemplate">
<Path Stroke="{DynamicResource Mobius.UI.Resources.Colors.ObstacleShapeOutlineBrush}" StrokeThickness="{Binding WorldAndScreen.MetersPerPixel, Converter={StaticResource Multiplier}, ConverterParameter=1}" StrokeLineJoin="Bevel" StrokeEndLineCap="Square" StrokeStartLineCap="Flat">
<Path.Fill>
<VisualBrush Stretch="Uniform" ViewportUnits="Absolute" TileMode="Tile">
<VisualBrush.Transform>
<ScaleTransform ScaleY="{Binding WorldAndScreen.MetersPerPixel, Converter={StaticResource Multiplier}, ConverterParameter=5}" />
</VisualBrush.Transform>
<VisualBrush.Visual>
<Image Stretch="None">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="{DynamicResource Mobius.UI.Resources.Colors.ObstacleShapeFillBrush}">
<GeometryDrawing.Geometry>
<GeometryGroup FillRule="Nonzero">
<PathGeometry>
<PathFigure StartPoint="0,0">
<LineSegment Point="1,0" />
<LineSegment Point="1,1" />
<LineSegment Point="0,1" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="{DynamicResource Mobius.UI.Resources.Colors.ObstacleShapeOutlineBrush}">
<GeometryDrawing.Geometry>
<GeometryGroup FillRule="Nonzero">
<PathGeometry>
<PathFigure StartPoint="0,0">
<LineSegment Point="0,.33" />
<LineSegment Point="1,.33" />
<LineSegment Point="1,0" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</VisualBrush.Visual>
</VisualBrush>
</Path.Fill>
<Path.Data>
<PathGeometry FillRule="Nonzero" Figures="{Binding Figures, FallbackValue={StaticResource DefaultFigures}}" />
</Path.Data>
</Path>
</DataTemplate>

Is there opportunity to combine rectangles to one rectangle?

I have some rectangles which their heights are same. But i filled them with different color. Can i combine them as result i get Rectangle? I can do it with RectangleGeometry but i need Rectangle type
How do you want to combine the colours?
Do you just want to specify 2 rectangular regions which overlap but use different colors with a level of transparency so that the colours blend together?
Or do you want the Rectangle subdivided and using different colours in different regions?
Is there a reason you need to keep it as a Rectangle?
Here's a way to keep it as a Rectangle but specify your 2 colours to combine/mix as the Fill:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Rectangle Width="100" Height="100">
<Rectangle.Fill>
<DrawingBrush Viewport="0,0,1,1" TileMode="Tile">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,1,1" />
</GeometryDrawing.Geometry>
<GeometryDrawing.Brush>
<SolidColorBrush Color="Red" Opacity="1"/>
</GeometryDrawing.Brush>
</GeometryDrawing>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,1,1" />
</GeometryDrawing.Geometry>
<GeometryDrawing.Brush>
<SolidColorBrush Color="White" Opacity=".5"/>
</GeometryDrawing.Brush>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
</Page>
Or this one for subdivided rectangles:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Rectangle Width="100" Height="100">
<Rectangle.Fill>
<DrawingBrush Viewport="0,0,1,1" TileMode="None">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,1,1" />
</GeometryDrawing.Geometry>
<GeometryDrawing.Brush>
<SolidColorBrush Color="Yellow"/>
</GeometryDrawing.Brush>
</GeometryDrawing>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,0.5,0.5" />
</GeometryDrawing.Geometry>
<GeometryDrawing.Brush>
<SolidColorBrush Color="Red"/>
</GeometryDrawing.Brush>
</GeometryDrawing>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0.5,0.5,0.5,0.5" />
</GeometryDrawing.Geometry>
<GeometryDrawing.Brush>
<SolidColorBrush Color="Green"/>
</GeometryDrawing.Brush>
</GeometryDrawing>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0.25,0.25,0.25,0.25" />
</GeometryDrawing.Geometry>
<GeometryDrawing.Brush>
<SolidColorBrush Color="Blue"/>
</GeometryDrawing.Brush>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
</Page>
(move the brush described by the DrawingBrush into Resources if you intend to use it in multiple places....and/or create a new Style for Rectangles).
Rectangle is sealed so it can be overridden, and it's not a Control so you can't change a template.
You might want to consider doing your own "Shape", so that you can better encapsulate the enhanced behaviour of "your" Rectangle.
Here's an example to get your started.
http://www.codeproject.com/Articles/21449/WPF-PartiallyRoundedRectangle-Choose-Which-Corners

Bind a property of the WPF Image

I have the following WPF UserControl
I want that the blue border be displayed only when the object has its (dependency bool property) property IsSelected to true.
Is that possible?
<Canvas>
<Image x:Name="Dot">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Brush="Blue" Thickness="2" x:Name="BigCircleThickness"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<GeometryGroup>
<EllipseGeometry x:Name="BigCircle" Center="0,0" RadiusX="7" RadiusY="7"/>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing>
<GeometryDrawing.Brush>
<SolidColorBrush Color="Blue" />
</GeometryDrawing.Brush>
<GeometryDrawing.Geometry>
<GeometryGroup>
<EllipseGeometry x:Name="SmallCircle" Center="0,0" RadiusX="2" RadiusY="2"/>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</Canvas>
In other words, I need that when IsSeleted = false "BigCircle" dissapear.
Is that possible?
You could use a DataTrigger. Something like this:
<Image>
<Image.Style>
<Setter Property="Source" Value={StaticResource MyDrawingImage_NoBorder}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="Source" Value={StaticResource MyDrawingImage_WithBorder}" />
</DataTrigger>
</Style.Triggers>
</Image.Style>
</Image>

How to fill an overlapped area when FillRule fails?

I'm trying to draw a hand-made DB drum alike shape. The problem is that the top ellipse is not completely filled.
Sample:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Image Width="126" Height="42" Margin="3" HorizontalAlignment="Left" VerticalAlignment="Top">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<GeometryDrawing Brush="Silver">
<GeometryDrawing.Pen>
<Pen Brush="Black" Thickness="1" LineJoin="Bevel" EndLineCap="Round" StartLineCap="Round" />
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<GeometryGroup FillRule="NonZero">
<EllipseGeometry Center="62,8" RadiusX="62" RadiusY="5" />
<PathGeometry>
<PathFigure StartPoint="0,8" IsClosed="False">
<LineSegment Point="0,38" />
<QuadraticBezierSegment Point1="60,49" Point2="124,38" />
<LineSegment Point="124,8" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</Grid>
</Page>
Any alternatives to solve this issue?
Thanks.
Finally... the solution was to make two separate path figures using arc segments:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Image Width="126" Height="42" Margin="3" HorizontalAlignment="Left" VerticalAlignment="Top">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<GeometryDrawing Brush="Silver">
<GeometryDrawing.Pen>
<Pen Brush="Black" Thickness="1" LineJoin="Bevel" EndLineCap="Round" StartLineCap="Round" />
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<GeometryGroup x:Key="Drum" FillRule="NonZero">
<PathGeometry>
<PathFigure StartPoint="0,6" IsClosed="True">
<ArcSegment Point="125,6" IsLargeArc="False" IsStroked="True" SweepDirection="Clockwise" Size="15,1.5" />
<ArcSegment Point="0,6" IsLargeArc="False" IsStroked="True" SweepDirection="Clockwise" Size="15,1.5" />
</PathFigure>
</PathGeometry>
<PathGeometry>
<PathFigure StartPoint="0,6" IsClosed="True">
<ArcSegment Point="125,6" IsLargeArc="False" IsStroked="True" Size="15,1.5" IsSmoothJoin="True" />
<LineSegment Point="125,35" IsSmoothJoin="True" />
<ArcSegment Point="0,35" IsLargeArc="False" IsStroked="True" SweepDirection="Clockwise" Size="15,1.5" IsSmoothJoin="True" />
<LineSegment Point="0,6" IsSmoothJoin="True" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</Grid>
</Page>

Resources