Adding Enumeration Value to Silverlight Attribute/Property - wpf

In the <ImageBrush/> element, there are AlignmentX and AlignmentY attributes with values Left/Center/Right and Top/Center/Bottom, respectively.
What I'm wanting to do is set my own value in, for example, AlignmentX either as a value or as another enumeration like AlignmentX="HalfCenter" where HalfLeft equals my own value (halfway between Center and Left). For example, if I have this:
<Rectangle Canvas.Left="0" Stroke="LimeGreen" StrokeThickness="16" Canvas.Top="0"
Width="400" Height="400" >
<Rectangle.Fill>
<ImageBrush ImageSource="newone.jpg"
Stretch="None" AlignmentX="HalfLeft" AlignmentY="Top" />
</Rectangle.Fill>
</Rectangle>
I don't know if this is a Dependency Property, Attached Property or otherwise (don't yet know how to create those). In the helpfile, it says in TileBrush.AlignmentXProperty field: Public Shared ReadOnly AlignmentXProperty As DependencyProperty. Does the ReadOnly word here mean that I can't set this property to a custom property?
If this can't be an override of that property, how can I create my own? I think this is an Attached Property and it could be called something different, like OffsetX and OffsetY that set an ImageBrush to a location inside its parent Shape. I'm getting very confused by the SL documentation on how I would do this though (almost no examples in VB.NET - but even the C# ones aren't all that revealing).
If it is possible, how would I get started on this?

Save yourself the pain and just use a value convertor and even that is going to be a little tricky, since you are going to have to apply a rendertransform or something to react to your enums.
You also could write your own panel which is probably a better idea.
You have a few different problems here to confront, creating the attached property, validating the enum, having the enum do what you want it to do when it is set.
Your also going to have to learn about MeasureOverride and ArrangeOverride
If you just can't help yourself ... Look Here

Related

How do I bind to the X position of a MouseDragElementBehavior?

My goal is to display the X position of my control in a TextBlock as I drag it around.
xmlns:mb="http://schemas.microsoft.com/xaml/behaviors"
<cc:CardControl Name="SevenOfSpades" Canvas.Left="350" Canvas.Top="124" Width="60" Height="80" Face="S7">
<mb:Interaction.Behaviors>
<mb:MouseDragElementBehavior ConstrainToParentBounds="True"/>
</mb:Interaction.Behaviors>
</cc:CardControl>
<TextBlock Text="{Binding ElementName=SevenOfSpades, Path=(mb:Interaction.Behaviors)[0].X}"/>
I'm struggling with the syntax of the Binding Path. At runtime I get an exception:
InvalidOperationException: Property path is not valid. 'Interaction' does not have a public property named 'Behaviors'.
The property is there because the drag works when the TextBlock is removed. I've tried various combinations of parentheses, I even tried x:static. Any help?
Edit
Having reread WPF Attached Property Data Binding, it does not solve my problem. Path= is in the Xaml and parentheses are included. The error is not a binding error it's a runtime error that occurs inside InitializeComponent.
MouseDragElementBehavior is part of the Microsoft.Xaml.Behaviors.Wpf Nuget package installed into my project.
Ah, ok. In that case, the code for MouseDragElementBehavior is most certainly available, and even if it wasn't you could just open up the assembly with JustDecompile or something and browse it that way.
If you check the documentation for MouseDragElementBehavior you'll see this:
XProperty Dependency property for the X position of the dragged
element, relative to the left of the root element.
So basically you're trying to bind one dependency property (TextBlock.Text) to another (MouseDragElementBehavior.X), but in order for this to work they have to be part of the same visual or logical tree (which they aren't, MouseDragElementBehavior is a behavior). If one of them was an attached property then you could bind them directly, but in your case you have to link them together with either a property in your DataContext that supports INPC, or some kind of proxy object.
However, even if you do this, you're going to run into problems. If you click the "Go to Live Visual Tree" button while your application is running and look at the properties for your SevenOfSpades control you'll see this:
So far, so good. Now drag the control around a bit and repeat this process. Suddenly a RenderTransform field has appeared:
Looking back at the code for MouseDragElementBehavior reveals that sure enough, that behaviour does the drag by changing the render transform.
So basically you're trying to set the position with Canvas.Top/Canvas.Left, but the behaviour is setting it by applying a render transform offset. Pick one. I personally use MVVM where everything is implemented in the view model layer, so it's easy to bind Canvas.Top/Canvas.Left to properties there. If you want to continue using MouseDragElementBehavior then you'll need to bind both the position of your cards, as well as your TextBlock text, to the render transform instead:
<Canvas>
<Rectangle Name="SevenOfSpades" Width="60" Height="80" Fill="Blue">
<Rectangle.RenderTransform>
<TranslateTransform X="350" Y="124" />
</Rectangle.RenderTransform>
<mb:Interaction.Behaviors>
<mb:MouseDragElementBehavior ConstrainToParentBounds="True" />
</mb:Interaction.Behaviors>
</Rectangle>
<TextBlock Text="{Binding ElementName=SevenOfSpades, Path=RenderTransform.Value.OffsetX}" />
</Canvas>

Can you set a Canvas the Background of an element in WPF?

Apologies if this has been asked but I can't find the answer. I have a couple of items (Windows, UserControls and DockPanels) that need dynamic backgrounds.
A Canvas object suits my needs well for the dynamic drawing, however, what I can't figure out is how (or even if) I can set a <Canvas> object as the value of a Background for a control object.
Can this be done and if yes, how?
Yes you can do that.
<Window.Background>
<VisualBrush>
<VisualBrush.Visual>
<Rectangle Width="50" Height="50" Fill="Red"></Rectangle><!-- Replace this with a reference to your Canvas-->
</VisualBrush.Visual>
</VisualBrush>
</Window.Background>
Code is referenced from this site there is a lot more that you can do with that background as well. Like set clipping etc ...
Note
Because you haven't specified the language you are developing it, I provided answer in the language I use namely C#, I don't use VB.
Dou you want to set the Background property of a control with the "contents" of a Canvas already populated with elements?
If so, yes; it's possible to accomplish this task creating a Brush from your Canvas. To do it, you need the VisualBrush class. In VB.NET, use something like this:
Dim oBrush As New VisualBrush(myCanvas)
myControl.Background = oBrush
Good luck, good code

The .To function in Silverlight

this.onePX.To = 64;
With the XAML:
<Rectangle Width="32" Height="32" Fill="Black" x:Name="onePX" Grid.Column="0" Grid.Row="0">
<Rectangle.RenderTransform>
<TranslateTransform />
</Rectangle.RenderTransform>
</Rectangle>
but for some reason, it returns with:
System.Windows.Shapes.Rectangle does not contain a definition for "To" and no extension method "To"...
Any idea why this could be happening, I tried to Google it, but searching for ".To" doesn't exactly yield accurate results ^.^
A Silverlight Rectangle does not have a "To" member (or method etc), so the compiler is quite right.
What are you actually trying to do the the Rectangle? That might result in better answers.
Edit 2
Ok, if you want to move a rectangle (on a pixel basis I assume as you said to an X,Y coordinate) you 1st need to parent it under a Canvas. Only a canvas renders children on a pixel basis.
Secondly to actually move a child of a Canvas, you need to set the attached properties Canvas.LeftProperty and Canvas.TopProperty.
You can either do this using the static methods Canvas.SetLeft(onePX, newValue) and Canvas.SetTop(onePx, newValue) (which take the child object and new values as parameters), or you can use the other SetValue syntax which looks like this.onePX.SetValue(Canvas.LeftProperty, newValue) and this.onePx.SetValue(Canvas.LeftProperty, newValue) etc.
The first static-method syntax is usually shorter and easier on the eyes :)
Hope this helps.

WPF: Setting named color to resource?

I am modifying the control template of the WPF Calendar control to change the color of text and the Previous and Next arrows on the control. I want to set the color to a local SolidColorBrush resource called MyTextBrush.
The Previous and Next buttons have separate control templates, and each draws a Path object for its button's arrow. Here is the relevant markup for the Previous button:
<Path Margin="14,-6,0,0" Height="10" Width="6" VerticalAlignment="Center" HorizontalAlignment="Left" Stretch="Fill" Data="M288.75,232.25 L288.75,240.625 L283,236.625 z">
<Path.Fill>
<SolidColorBrush x:Name="TextColor" Color="#FF333333" />
</Path.Fill>
</Path>
Note that the color is named TextColor, using the x:Name property.
Here is my problem: The x:Name property is required--WPF throws an exception if it is missing. That means I can't simply replace the entire brush with a reference to the MyTextBrush resource, because I would lose the x:Name value. So, how do I reference MyTextBrush, while still retaining the x:Name property for the brush in this particular control template?
Thanks for your help.
So, how do I reference MyTextBrush,
while still retaining the x:Name
property for the brush in this
particular control template?
Regarding this problem it sounds like you are using a dodgy/fragile template. What control template is it?
If you have full source control of the template, remove references to the named element (most likely in a storyboard). They must be animating the brush for some reason.
The other option might be to just create another unused brush within your template (Perhaps on a hidden element) with the correct name to keep the template happy.
Lastly, you can try adding the x:Name onto the brush in the shared RD, but this is quite complicated and not sure its worth it!
Two more potential solutions:
Try binding just the Color property of the SCB... that should work as its a DP
Change the template animations so they do not use a named brush, but instead use a named parent then access the brush via the TargetProperty e.g. Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="myNamedParent"
The best solution seems to be to break the Color property out to its own tag, and use a resource reference for that. Here is what it looks like:
<!-- FS: Changed template brush color -->
<SolidColorBrush x:Name="TextColor">
<SolidColorBrush.Color>
<StaticResource ResourceKey="FsTextColor" />
</SolidColorBrush.Color>
</SolidColorBrush>

Databind RenderTransform Scaling in Silverlight 2 Beta 2

Anyone know if it's possible to databind the ScaleX and ScaleY of a render transform in Silverlight 2 Beta 2? Binding transforms is possible in WPF - But I'm getting an error when setting up my binding in Silverlight through XAML. Perhaps it's possible to do it through code?
<Image Height="60" HorizontalAlignment="Right"
Margin="0,122,11,0" VerticalAlignment="Top" Width="60"
Source="Images/Fish128x128.png" Stretch="Fill"
RenderTransformOrigin="0.5,0.5" x:Name="fishImage">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1"/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
I want to bind the ScaleX and ScaleY of the ScaleTransform element.
I'm getting a runtime error when I try to bind against a double property on my data context:
Message="AG_E_PARSER_BAD_PROPERTY_VALUE [Line: 1570 Position: 108]"
My binding looks like this:
<ScaleTransform ScaleX="{Binding Path=SelectedDive.Visibility}"
ScaleY="{Binding Path=SelectedDive.Visibility}"/>
I have triple verified that the binding path is correct - I'm binding a slidebar against the same value and that works just fine...
Visibility is of type double and is a number between 0.0 and 30.0. I have a value converter that scales that number down to 0.5 and 1 - I want to scale the size of the fish depending on the clarity of the water. So I don't think it's a problem with the type I'm binding against...
ScaleTransform doesn't have a data context so most likely the binding is looking for SelectedDive.Visibility off it's self and not finding it. There is much in Silverlight xaml and databinding that is different from WPF...
Anyway to solve this you will want to set up the binding in code**, or manually listen for the PropertyChanged event of your data object and set the Scale in code behind.
I would choose the latter if you wanted to do an animation/storyboard for the scale change.
** i need to check but you may not be able to bind to it. as i recall if the RenderTransform is not part of an animation it gets turned into a matrix transform and all bets are off.
Is it a runtime error or compile-time, Jonas? Looking at the documentation, ScaleX and ScaleY are dependency properties, so you should be able to write
<ScaleTransform ScaleX="{Binding Foo}" ScaleY="{Binding Bar}" />
... where Foo and Bar are of the appropriate type.
Edit: Of course, that's the WPF documentation. I suppose it's possible that they've changed ScaleX and ScaleY to be standard properties rather than dependency properties in Silverlight. I'd love to hear more about the error you're seeing.
Ah I think I see your problem. You're attempting to bind a property of type Visibility (SelectedDive.Visibility) to a property of type Double (ScaleTransform.ScaleX). WPF/Silverlight can't convert between those two types.
What are you trying to accomplish? Maybe I can help you with the XAML. What is "SelectedDive" and what do you want to happen when its Visibility changes?
Sorry - was looking for the answer count to go up so I didn't realise you'd edited the question with more information.
OK, so Visibility is of type Double, so the binding should work in that regard.
As a workaround, could you try binding your ScaleX and ScaleY values directly to the slider control that SelectedDive.Visibility is bound to? Something like:
<ScaleTransform ScaleX="{Binding ElementName=slider1,Path=Value}" ... />
If that works then it'll at least get you going.
Edit: Ah, I just remembered that I read once that Silverlight doesn't support the ElementName syntax in bindings, so that might not work.
Yeah maybe the embedded render transforms aren't inheriting the DataContext from the object they apply to. Can you force the DataContext into them? For example, give the transform a name:
<ScaleTransform x:Name="myScaler" ... />
... and then in your code-behind:
myScaler.DataContext = fishImage.DataContext;
... so that the scaler definitely shares its DataContext with the Image.
Ok, is the Image itself picking up the DataContext properly?
Try adding this:
<Image Tooltip="{Binding SelectedDive.Visibility}" ... />
If that compiles and runs, hover over the image and see if it displays the right value.
I was hoping to solve this through XAML, but turns out Brian's suggestion was the way to go. I used Matt's suggestion to give the scale transform a name, so that I can access it from code. Then I hooked the value changed event of the slider, and manually updates the ScaleX and ScaleY property. I kept my value converter to convert from the visibility range (0-30m) to scale (0.5 to 1). The code looks like this:
private ScaleConverter converter;
public DiveLog()
{
InitializeComponent();
converter = new ScaleConverter();
visibilitySlider.ValueChanged += new
RoutedPropertyChangedEventHandler<double>(visibilitySlider_ValueChanged);
}
private void visibilitySlider_ValueChanged(object sender,
RoutedPropertyChangedEventArgs<double> e)
{
fishScale.ScaleX = (double)converter.Convert(e.NewValue,
typeof(double), null, CultureInfo.CurrentCulture);
fishScale.ScaleY = fishScale.ScaleX;
}

Resources