WPF - Drawing image to canvas and erasing and redrawing repeatedly - c#

I currently have a canvas with an image background in a WPF application. Above this canvas, I have a slider control. I need to, as users slide the value of the slider back and forth, draw a red line straight down across the canvas. I need to do this every time the slider value is changed such that the red line is always aligned with the slider's thumb. The big problem I'm having here is trying to figure out how to efficiently draw the line, and then "erase" the previously drawn line and drawing a new line at the new thumb value when user's change the slider's value. If I simply redraw the canvas's background image, the application lags a lot and doesn't work well (plus, this just straight out doesn't completely solve the problem as you can still see the previously drawn lines anyway).
Any help would be absolutely appreciated, particularly with examples as I this is my first WPF application in C# and I'm stilling getting a feel for it's uniqueness (as opposed to Windows Forms). Thanks a lot!

Rather than trying to draw the line yourself, a more WPF way to approach it would be to use a Line object. See Shapes and Basic Drawing in WPF Overview. Since you want the line to be aligned with the Slider, you can use data binding to bind the X position of the line to the position of the Slider:
<DockPanel>
<Slider
Name="HorizontalSlider"
DockPanel.Dock="Top"
Maximum="{Binding ActualWidth, ElementName=Canvas}"/>
<Canvas Name="Canvas" Margin="5.5 0">
<Line
X1="{Binding Value, ElementName=HorizontalSlider}"
Y1="0"
X2="{Binding Value, ElementName=HorizontalSlider}"
Y2="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Canvas}}"
Stroke="Red"/>
</Canvas>
</DockPanel>
(Note that I cheated a little by setting the margin on the Canvas to 5.5. The thumb on the slider has some thickness and doesn't move the entire width of the slider control, so in order to get the line to line up with the center I tried to make the canvas have the same width as the track.)

Related

How can I set multiple backgrounds for a grid in WPF?

I have a grid, which has 2 rows and 3 columns.
I need 2 background images for my grid - one will be on the top of the other. (ZIndex of one background should be bigger than other background has). How can I achieve this?
I will need to swap these 2 backgrounds frequently, which means the top background will become lower background and lower background will become top background. Apart from that, images of these two backgrounds are gonna change a lot too.
This example has grid, which contains text switcher at the bottom. As a background, it has a picture of room. When I click 'next' button in the text switcher, I want the top background picture to gradually disappear (doubleAnimation updates opacity) and show lower background under it. Maybe I can achieve gradual switching of backgrounds in a better way, but I honestly dont know how to do it.
You can draw them as two images on a Canvas inside a VisualBrush and use that as your background:
<Grid>
<Grid.Background>
<VisualBrush>
<VisualBrush.Visual>
<Canvas Width="256" Height="256">
<Image Source="image1.png" Panel.ZIndex="1" /> <!-- This will appear over top of the other one -->
<Image Source="image2.png" Panel.ZIndex="0" />
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
</Grid.Background>
</Grid>
Source and Panel.ZIndex can then be set either directly in code-behind or via data binding.
This is a bit of an unsual way of going about this though, there's almost certainly a better way of doing whatever it is you're actually trying to do.
In this case I would use databinding to bind to a property in the view model that stores the background image. When the condition changes and the view model property is changed the UI will reflect those changes.

Avalonia UI Pop-Up Overlay

My question is pretty straight forward:
How do I achieve an Overlay Pop-Up effect using avalonia?
What I mean by this is I want to darken the whole Panel that contains my UI elements a little bit (tried the opacity attribute, but it didn't look good and the OpacityMask only seems to support "Transparent" as a color, but I want semi-transparency or even blur if that's possible). Then I want to display a little popup box. If this were CSS I'd be able to do a position: absolute;, however I couldn't figure out how to do this using avalonia.
To visualize what I mean here are some screenshots of a Windows Forms Application where I was able to achieve the desired effect:
My UI without overlay effect:
My UI with overlay effect:
As you can see the whole UI has been darkened a bit while the background is still visible (when using the avalonia Opacity property the effect is not the same and quite inconsistent, as the more panels are on top of each other on a given position the less the background seems to be affected by the Opacity and it just doesn't look good. I can add screenshots of how bad it would look later if you want.)
To sum it up:
1. How do I slightly and consistently darken (or even blur?) a panel with all of its contents, so that stacked panels with the same background color don't become visible, just because the transparency is acting weird?
2. What is the avalonia equivalent to the CSS position: absolute; so I can put my Pop-Up in the middle of the screen and on top of everything else?
You can use the same technique as in WPF:
<Window>
<Grid>
<DockPanel x:Name="YourMainContentGoesHere"/>
<Border IsVisible="{Binding IsPopupVisible}" Background="#40000000">
<YourPopupControlHere Width="200" Height="200"/>
</Border>
</Grid>
</Window>
Unconfigured Grid will display elements on top of each other, semi-transparent Border's background will darken the rest of the content.

Why is the image only partially visible inside my Button?

I am developing a Windows Store app and I've done this before, months ago, but all of a sudden, in this new app, I can't get the image to display inside the button (properly).
<Button x:Name="ShowView" Grid.Column="1" Width="32" Height="32" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,61,20,33">
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Image x:Name="ShowViewImage" Source="/Assets/ShowView.png" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</StackPanel>
</Button>
As you can see, the code is fine (unless things have changed drastically, which by the looks of it they haven't). So what gives? This is the only code I have so far in my XAML file other than the defauls that VS generates as it's a new Project.
P.S. I've also tried taking out the StackPanel and just having Button > Image, but this produces the same result.
So, when the BUtton displays at runtime, all I can see is a very tiny, 2pixels of the image (but the image is actually 32x32pixels. How do I properly display an "Image Button"?
The problem is that your Width and Height for the button are far too small. You've made it 32x32 pixels, but the button will use almost all of that itself for the space it leaves around the visible border, the border itself, and the padding between the border and the button's content.
(It leaves space around the edge to provide a larger hit target than the visible appearance. This is useful on touchscreens, where accurate finger placement is difficult.)
All that's left for your image is a few pixels.
You'll need to make the button about 62x52 pixels to leave enough space in the middle for a 32x32 pixel bitmap.
You could get away with a slightly smaller button if you explicitly set smaller Margin and Padding properties, although as mentioned above, the margin is there for a reason.
You have a couple options, the Padding property for instance is Template bound with some pre-set padding added to it. So with your Button having a fixed Height and Width set to 32 something as simple as setting Padding="0" could fix it for you depending on the actual size of your Image.
If worse comes to worse though, you could always just make your own Button Template. There's a couple easy ways to do this. One of which would be just go make a copy of the default Button Template, rip out all the Padding/Margin/Height/Width crap preset in there and just change its name then apply your new template directly to your button like;
<Button x:Name="ShowView" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,61,20,33"
Style="{StaticResource YourCustomButtonTemplateForImages}">
<Image x:Name="ShowViewImage" Source="/Assets/ShowView.png"/>
</Button>
Or... another option would be, embed your Image inside of a ViewBox inside your button and it will fit and re-scale itself accordingly to its set available size.
Oh, you might also want to make your Background="Transparent" while you're at it to make it look a little cleaner as just an image.
Hope this helps.

How to animate an object to the Center of a fluid layout in Silverlight

Hi and thanks for reading.
I am building a simple silverlight page and having difficulties animating elements to the center the screen.
The example...
MouseLeftButtonDown > animate the rectangle to the center of the screen.
Is there a way to do this?
The way I handle this in my MVVM application is to bind the location of the rectangle to a ViewModel object. When that position is updated, the rectangle moves. I then have a behavior tied to the LayoutUpdated event of the rectangle itself that uses a translate transform to move the item back to its original location and then runs an animation over that translate transform to move the X and Y values down to 0, so the item animates to its "real" location.
<Border Width="{Binding PositionRectangle.Width}"
Height="{Binding PositionRectangle.Height}"
BorderBrush="{Binding OptionColorBrush}"
BorderThickness="3">
<Border.RenderTransform>
<TransformGroup>
<TranslateTransform/>
<ScaleTransform/>
</TransformGroup>
</Border.RenderTransform>
<i:Interaction.Triggers>
<i:EventTrigger EventName="LayoutUpdated">
<ic:AnimationTriggerAction LocationPropertyName="Location"/>
</i:EventTrigger>
<i:EventTrigger EventName="Loaded">
<ic:AnimationTriggerAction LocationPropertyName="Location"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBlock Text="{Binding Name}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
TextWrapping="Wrap"/>
</Border>
The Trigger I am using (AnimationTriggerAction) was hand-rolled, since I wanted it to do a few other things as well (e.g. it handles running a scale animation over the item when it is first loaded as well, so it scales itself into existence), but nothing here is too difficult. It descends from TargetedTriggerAction<FrameworkElement> and keeps track of the object's previous location in a dependency property on that item. It creates the storyboard if it doesn't exist and adds 2 DoubleAnimations to it to run over the X and Y properties of the TranslateTransform.
Positive points to this approach:
No need to handle events in the .xaml.cs to fire up the animations. It all happens from the LayoutUpdated and Loaded events.
The fact that animations are occurring is entirely hidden from the ViewModel.
Negative points:
There is a slight flicker as the object snaps into existence and then the translate transform is set, so it snaps back to the original location before the animation starts. It's very subtle but it is there.
This isn't really ready for public consumption yet, but my proof of concept for this is located here: http://www.benvonhandorf.com/Apps/WOM/WheelOfMeat.html Enter an option name in the textbox and hit enter and you should see the option fade into existance. Enter a few more and you'll see them rearrange themselves around the wheel.

Surface ScatterViewItem background not transparent

I'm working on a Microsoft Surface and attaching a round image object to a ScatterViewItem. I'm having an issue hiding the background of the square ScatterViewItem. If I go in and set the background to transparent, it's not transparent, it's more like gray translucent. So what I end up with is a round image in the middle sitting on a square with gray translucent edges. How do I hide this? I'm doing this programmatically through C#.
What you're seeing isn't really the svi background, but the shadow that is part of the default template. If you want to get rid of the shadow, you need to redefine the control template.
So like this:
<s:ScatterView>
<s:ScatterViewItem Background="Transparent">
<s:ScatterViewItem.Template>
<ControlTemplate>
<TextBlock>Hello World</TextBlock>
</ControlTemplate>
</s:ScatterViewItem.Template>
</s:ScatterViewItem>
</s:ScatterView>
Be aware that if you replace it like that, you lose all the other little visual flare like the 'pick up' effect and the shimmer. If you want to keep those, just use blend to edit a copy of the existing template and remove the shadow.

Categories

Resources