What are the Silverlight 3 alternatives to DynamicResource and Element-based Brushes? - silverlight

I need to have a custom UI element that can be changed, such as the colour and text used in the application but as a resource - in WPF I can use a DynamicResource to assign brushes, strings etc, however I need to implement this in Silverlight 3 - how can I do this as a StaticResource will not do, and as another question I have a resource which is made of other UI-Elements like Rectangles. See example from my existing ResourceDictionary:
<VisualBrush x:Key="Device" Stretch="Uniform">
<VisualBrush.Visual>
<Canvas Width="20" Height="36">
<Rectangle Height="36" Width="20" Fill="{DynamicResource ZuneColour}" Canvas.Left="0" Canvas.Top="0" RadiusX="1" RadiusY="1">
<Rectangle.BitmapEffect>
<OuterGlowBitmapEffect GlowColor="Black" GlowSize="2" />
</Rectangle.BitmapEffect>
</Rectangle>
<Rectangle Fill="{DynamicResource ZuneScreen}" Canvas.Left="1" Canvas.Top="1" Height="24" Stroke="#191616" Width="18"/>
<Rectangle Canvas.Left="5.5" Canvas.Top="25" Height="9" Width="9" RadiusX="3" RadiusY="3" Fill="{DynamicResource ZunePad}" Stroke="{DynamicResource ZunePadOuter}"/>
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
I have also had an issue with replicating the OuterGlowEffect, but at least this can be done with a compiled DirectX effect so can leave this out if needed.
I think Data Bindings will be a good solution to dynamic content as can create a Class which
stores the visual data I need and this can be a One-way binding to update the UI - hopefully this may be useful to others with the same issue.
Still need to replace VisualBrush functionality with something that will work in Silverlight for the given example.

Related

WPF / Xaml, vertical aligment of LineGeomtry inside grid not working properly

I try to get into creation of custom controls with for WPF. I found many good
tutorials and advises on the web so I started width a really simple example to get
my hands dirty and get some practice. I figured out that the issue stumbled across
is not really related to the subject of custom controls. So I extracted the xaml code to a simple wpf form.
<Window x:Class="WpfVerticalAigmentTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="200" Width="200">
<Grid>
<Grid Height="40" Background="LightCyan" VerticalAlignment="Center">
<Path Stroke="Red"
StrokeThickness="20" VerticalAlignment="Center" >
<Path.Data>
<LineGeometry StartPoint="0,0" EndPoint="100,0"></LineGeometry>
</Path.Data>
</Path>
</Grid>
</Grid>
My expectation was to get a line centered in the grid and claiming the half of the stroke thickness on each side from the center. But as the linked image shows differs from my expectation.
"Resulting visualization"
So it look like I missed a detail about the line shape or linegeomtry. How do I get the the line displayed as shown in the following image?
"Expected result"
You need to match the Width and Height of the LineGeometry to the Width and Height of the Path and set the VerticalAlignment property to Bottom:
<Grid Height="20" Width="200" Background="LightCyan" VerticalAlignment="Center">
<Path Stroke="Red" StrokeThickness="20" VerticalAlignment="Bottom">
<Path.Data>
<LineGeometry StartPoint="0,0" EndPoint="200,0"></LineGeometry>
</Path.Data>
</Path>
</Grid>
If your goal is your the expectaions, and not the way how u have reached this, I could prefer to you this:
<Grid>
<Grid Height="40" Background="LightCyan" VerticalAlignment="Center">
<Border BorderThickness="10" VerticalAlignment="Center" BorderBrush="Red" />
</Grid>
</Grid>
The problem here is that the starting point of the XY Coordinates of the Path starts on the top left, and the stroke expands in both directions but thereby only makes the Path bigger to the bottom (I can't really tell you why, but that's just what seems to happen).
You can see this pretty good in the Design View:
To work around this simply move your Y Coordinates down half of the stroke size.
<Grid Height="40"
VerticalAlignment="Center"
Background="LightCyan">
<Path VerticalAlignment="Center"
Stroke="Red"
StrokeThickness="20">
<Path.Data>
<LineGeometry StartPoint="0,10" EndPoint="100,10" />
</Path.Data>
</Path>
</Grid>
Or wrap it in another control (Canvas is the commonly used controls for Paths) with the desired height:
<Grid Height="40"
VerticalAlignment="Center"
Background="LightCyan">
<Canvas Height="20" VerticalAlignment="Center">
<Path Stroke="Red"
StrokeThickness="20">
<Path.Data>
<LineGeometry StartPoint="0,10" EndPoint="100,10" />
</Path.Data>
</Path>
</Canvas>
</Grid>
And you are good to go:

Reusable polygon

I want to have a canvas in xaml where i place some icons. These icons are polygons like this one:
<Polygon Points="0,0 20,50, 0,50 20,0" Fill="Red" Stretch="Uniform"/>
But i want to use an icon several times, so i want to define it in the resources and include it by reference into the canvas at a certain position, someway like this:
<Page.Resources>
<Polygon Key="icon1" Points="0,0 20,50, 0,50 20,0" Fill="Red" Stretch="Uniform"/>
<Polygon Key="icon2" Points="0,0 10,30, 10,60 20,0" Fill="Blue" Stretch="Uniform"/>
...
</Page.Resources>
<Canvas>
<Polygon Reference="icon1" X="0" Y="0"/>
<Polygon Reference="icon2" X="10" Y="10"/>
<Polygon Reference="icon1" X="20" Y="20"/>
...
</Canvas>
I found a possible solution on http://www.codeproject.com/KB/WPF/GraphicInXAMLAndWPF.aspx where the polygons are stored in a drawing image, but seems to be to much overhead.
Someone has an better idea how to solve this?
Probably the most obvious and flexible method is to create a UserControl. You can add a new file of type UserControl from the solution explorer, add your Polygon to the 'LayoutRoot' Grid that Visual Studio will create. You can then create as many instances as you like of your user control!
However, checking for similar problems on SO, you could use a content control to render the polygon, note, you would have to use x:Shared="false" to ensure that you are not trying to re-use the same polygon each time.
<Page.Resources>
<Polygon x:Key="icon1" x:Shared="False"
Points="0,0 20,50, 0,50 20,0" Fill="Red" Stretch="Uniform"/>
<Polygon x:Key="icon2" x:Shared="False"
Points="0,0 10,30, 10,60 20,0" Fill="Blue" Stretch="Uniform"/>
...
</Page.Resources>
<Canvas>
<ContentControl Content="{StaticResource icon1}" Canvas.Top="0" Canvas.Left="0"/>
<ContentControl Content="{StaticResource icon2}" Canvas.Top="0" Canvas.Left="10"/>
<ContentControl Content="{StaticResource icon1}" Canvas.Top="0" Canvas.Left="20"/>
...
</Canvas>
See the following:
Vector image as reusable XAML fragment

WPF: Altering a listbox style, smoothening transition between borders

I'm trying to alter the listboxitem style for a silverlight menu.
The result I need should look like something like this
Is this even possible?, if so:
How can i accieve this?
The current Xaml code used for the menu:
<Style x:Key="LeftMenuStyle" TargetType="ListBoxItem">
<StackPanel Orientation="Horizontal" Margin="12">
<Border BorderBrush="OliveDrab" CornerRadius="40" BorderThickness="5">
<Image Source="../Resources/cancel.png" Width="50" Height="50" />
</Border>
<Border CornerRadius="5" Width="180" >
<Border.Background>
<SolidColorBrush Color="OliveDrab"/>
</Border.Background>
<Border Padding="10,0,0,0">
<ContentPresenter VerticalAlignment="Center" Content="{TemplateBinding Content}" />
</Border>
</Border>
</StackPanel>
</Grid>
</ControlTemplate>
You could try to model that shape with Expression Design or a similar tool (actually I don't know if a similar tool exists); at least that's the easiest solution I'd go for. You can even import Adobe Illustrator files if it's easier to design the shapes there. And you obtain XAML that you can use directly, including any complex shapes.
Note: Expression Design is part of Expression Studio.
As a quick example (I just joined a circle and a rectangle together), the result XAML is this:
<Path Width="197" Height="64.5"
Canvas.Left="32.8333" Canvas.Top="41.6667" Stretch="Fill"
StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FFFFFFFF"
Data="F1 M 65.0833,42.1667C 76.8868,42.1667 87.186,48.6077 92.6577,58.1667L 229.333,58.1667L 229.333,90.1667L 92.3654,90.1667C 86.8243,99.4496 76.6798,105.667 65.0833,105.667C 47.5483,105.667 33.3333,91.4517 33.3333,73.9167C 33.3333,56.3817 47.5483,42.1667 65.0833,42.1667 Z "/>
And on that note, I strongly recommend using Adobe Illustrator or equivalent program and importing the files in Expression Design; its capabilities are still minimal when it comes to vector graphics, especially for someone used to AI. Also, you can import AI files directly into Blend.

Use UIElement as Clip in WPF

Please pardon my ignorance- I'm very new to WPF.
I am looking to implement a minor, visual effect in my application that gives the look of "inner" rounded corners. The window in question has a dark border that encapsulates several UIElements, one of which is a StatusBar, located at the bottom of the window. This StatusBar has a dark background that matches the window's border. Above the StatusBar is a content view, which is currently a Grid- its background is semi-transparent (I think that this is something of a constraint- you can see through the content view to the desktop below). I would like for the content view (represented by the transparent, inner area in the figure below) to have the look of rounded corners, though I expect to have to sort of create the illusion myself.
(Can't post the image because I'm a lurker and not a poster- please find the drawing here)
My first approach was to add a Rectangle (filled with the same, dark color as the border) immediately above the StatusBar and to assign a Border with rounded corners to its OpacityMask (similar to the solution proposed by Chris Cavanagh**). Sadly, the effect that is produced is the exact opposite of that which I am trying to achieve.
I understand that the Clip property can be of use in this sort of situation, but it seems to me that using any sort of Geometry will prove to be inadequate as it won't be dynamically sized to the region in which it resides.
EDIT: Including my XAML:
<Grid Background="{StaticResource ClientBg}" Tag="{Binding OverlayVisible}" Style="{StaticResource mainGridStyle}">
<DockPanel LastChildFill="True">
<!-- Translates to a StackPanel with a Menu and a Button -->
<local:FileMenuView DockPanel.Dock="Top" />
<!-- Translates to a StatusBar -->
<local:StatusView DockPanel.Dock="Bottom" />
<!-- Translates to a Grid -->
<local:ContentView />
</DockPanel>
</Grid>
Any pointers are more than welcome- I'm ready to provide more indepth detail if necessary.
** http://www.dotnetkicks.com/wpf/WPF_easy_rounded_corners_for_anything
EDIT: Now I got what you mean. In fact you can use Path + OpacityMask approach. You have to draw "inverted" path, to use it as opacity mask. But I have simpler and faster solution for you :). Use Border + CornerRadius, and fill the gaps with solid paths. Just try the following code in Kaxaml and let me know if this is what you were looking for:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="240"
Height="320"
AllowsTransparency="True"
Background="Transparent"
WindowStyle="None">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="24"/>
<RowDefinition Height="*"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<Border Background="Black"/>
<Border Grid.Row="1" BorderBrush="Black" BorderThickness="5">
<Grid>
<Border Background="White" CornerRadius="0, 0, 5, 5" Opacity="0.7"/>
<Path
Width="15"
Height="15"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Data="M10,10 L5,10 L5,5 C4.999,8.343 6.656,10 10,10 z"
Fill="Black"
Stretch="Fill"/>
<Path
Width="15"
Height="15"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Data="M10,10 L5,10 L5,5 C4.999,8.343 6.656,10 10,10 z"
Fill="Black"
Stretch="Fill">
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="-1"/>
<TranslateTransform X="15"/>
</TransformGroup>
</Path.RenderTransform>
</Path>
</Grid>
</Border>
<Border Grid.Row="2" Background="Black"/>
</Grid>
</Window>
PS: You can simplify this solution by avoiding render transforms, but you got the idea.

How to prevent the Visual Brush from stretching its content

In my project I want to display a small logo on the side of a custom control. Since I have no canvas I thought maybe a Visual Brush would be a good Idea to place the logo in the background.
<VisualBrush>
<VisualBrush.Visual>
<Rectangle Width="200" Height="200" Fill="Red" />
</VisualBrush.Visual>
</VisualBrush>
But the Rectangle I am using right now is not 200x200. It takes the complete available space. Thats not what I want. I also tried a Viewbox and set the stretch property but the result is the same because in the end I don't need a simple Rectangle but a canvas with many path objects as children. A Viewbox supports only one child.
This there any way to get around this problem?
You need to set TileMode, Stretch, AlignmentX and AlignmentY properties on your VisualBrush:
<VisualBrush TileMode="None" Stretch="None" AlignmentX="Left" AlignmentY="Top">
<VisualBrush.Visual>
<Rectangle Height="200" Width="200" Fill="Red"></Rectangle>
</VisualBrush.Visual>
</VisualBrush>
Add Grid and this Set Vertical alligment to Top and Horizontal alignment to Right
Sample code
<VisualBrush x:Key="myVisual">
<VisualBrush.Visual>
<Grid>
<Rectangle Height="200" Width="200" Fill="Red" HorizontalAlignment="Right" VerticalAlignment="Top" ></Rectangle>
</Grid>
</VisualBrush.Visual>
</VisualBrush>
For me, I set the following attribute on the VisualBrush, and the VisualBrush now looks exactly like a MediaElement:
Stretch="Uniform"

Resources