Animating from a point other than the left side - wpf

I have an animation problem that I'm not sure how to Google or find a solution for. I'm trying to basically create a wrapping Marquee. I do this by having the following within a canvas:
|---Section A---|---Section B---|Section C---|
The animation begins with the left side of section B on the right side of the screen, and ends when the right side of section B hits the left side of the screen. Sections A and C are a mirror image of Section B, which creates the "wrap around" effect. When the animation ends, I move everything to the right the exact width of Section B. To the user, nothing appears to have happened .. it's all just wrapping around.
The problem is this ... some of the items in the marquee can be hidden, or can change size. So if you hide an item, the item is hidden from all three sections. Since things are being hidden in Section A, and all the sections are sized dynamically, the entire marquee moves to the left.
Is there any way to "anchor" the animation at a spot, say, in the middle of Section B, so that when items are hidden in section A, it doesn't slide sections B and C over? Instead, I want Section A to move right to fill in the space.
Edit: Let me rephrase ... because this is confusing.
I have a canvas, which contains a stackpanel, which contains three more stack panels. These three stack panels are actually copies of the same information, which gives the illusion of a marquee that wraps around when I animate. When items are added/removed in the marquee, those items in the stack panel change, which adjusts the overall size of the stack panel, which adjusts the size of the canvas. What I'd like to know, is if I can "anchor" a specific location within the stackpanel. Can I "anchor" on the first item in the 2nd stackpanel copy?

To answer what APPEARS to be the primary question:
Is there a way to animation the position of a canvas using something
other than the Canvas.Left property
Set the RenderTransform property of the Canvas to a TranslateTransform and animate the TranslateTransform.X Property:
<Canvas x:Name="myCanvas" RenderTransformOrigin="0.5,0.5">
<Canvas.RenderTransform>
<TranslateTransform X="0"/>
</Canvas.RenderTransform>
</Canvas>
Then in code:
EDIT: The second parameter of this method call should be of type DoubleAnimation, not Duration. I must have been sleeping at my desk when I typed this. Sorry.
(TranslateTransform)MyCanvas.RenderTransform.BeginAnimation(TranslateTransform.XProperty, new Duration(TimeSpan.FromSeconds(3)));
I hope this helps.

My other answer is becoming obsolete as you elaborate on your desired behavior, so forgive me for posting a second. Based on my latter comments on the above answer, consider the following example:
<Canvas x:Name="LayoutRoot">
<Grid x:Name="MarqueePanels">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle Grid.Column="0" Height="{Binding ElementName=PrimaryMarquee, Path=ActualHeight}" Width="{Binding ElementName=PrimaryMarquee, Path=ActualWidth}">
<Rectangle.Fill>
<VisualBrush Visual="{Binding ElementName=PrimaryMarquee}"/>
</Rectangle.Fill>
</Rectangle>
<StackPanel Grid.Column="1" x:Name="PrimaryMarquee">
<TextBlock Text="Marquee Item 1"/>
<TextBlock Text="Marquee Item 2"/>
<TextBlock Text="Marquee Item 3"/>
</StackPanel>
<Rectangle Grid.Column="2" Height="{Binding ElementName=PrimaryMarquee, Path=ActualHeight}" Width="{Binding ElementName=PrimaryMarquee, Path=ActualWidth}">
<Rectangle.Fill>
<VisualBrush Visual="{Binding ElementName=PrimaryMarquee}"/>
</Rectangle.Fill>
</Rectangle>
</Grid>
</Canvas>
As I mentioned above, setting the Visibility of any of the TextBox elements to Hidden will not cause the StackPanel parent to resize, however using Visibility.Collapsed WILL force an Arrange pass of the parent panel. So if you truly NEED to use a StackPanel to contain the visual elements, then I recommend based on your comments above using Visibility.Hidden in lieu of Visibility.Collapsed.
Also notice the use of VisualBrush to replicate the Marquee content. This will simplify the code, and ensure that all 3 visuals always match (with the exception of whatever positioning or transformation you apply to the Rectangle objects that house the VisualBrush).
Additionally, I should say that I personally would use a Canvas in lieu of the StackPanel, as the Canvas is much better suited for absolute positioning of child elements, hence the reason for your question.
Craig, I truly hope this helps. I (like most people on here) will try to help however I can. Good luck!

Got it.
I set the margin to -(theControl.ActualWidth / 2). All my code shifts everything back by that same amount to compensate.
Then I have an event handler for SizeChanged on the control, where I set this value. If the size of the control changes, the margin is update, and everything focuses on the middle of the control. If you have a specific point within the control that you want to center animation on, then use that point instead of the halfway point described above.

Related

TextTrimming in panel in ScrollViewer

I am trying to set up an element within a WPF application, but cannot get the TextTrimming on the TextBlocks to work properly. This is within a ScrollViewer. I am currently using a DockPanel as the inner container.
I have searched quite a bit, but found no questions addressing this issue.
The XAML for the container:
<Grid>
<ScrollViewer>
<DockPanel Name="listedCharacters" LastChildFill="False"></DockPanel>
</ScrollViewer>
</Grid>
The XAML for the child elements (added by code):
<UserControl …>
<Grid DockPanel.Dock="Top" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding FullName}" TextTrimming="CharacterEllipsis" />
</Grid>
</UserControl>
The first problem is that whether I use the DockPanel or a StackPanel, as the inner container, the child element's width appears to be dictated by its content (the TextBlocks) rather than constrained by the parent ScrollViewer.
The effect I want is for the ellipsis to truncate each TextBlock's content when the Window's grid column (not shown in code) is narrower than the bound text. Basically, a list that scrolls vertically when needed, and trims horizontally (which I thought would have been sufficiently common that the answer would be out there; alas, no).
I believe I need to use my own UserControl for this, as there is a lot more going on than shown her; right-click menus on the item in the list, etc.
The secondary issue, iff the optimal panel to use is the DockPanel, how to apply the DockPanel.Dock="Top" through code (C#) when the elements are dynamically added? Again, I cannot find anything that appears to explain this. (I know it is probably in the wrong place in the sample code above.)

How to make custom close button in wpf?

I want to create following form but problem is there when I'm setting the margin with negative value then it will not work and hide my cross image. Is this possible to create as it is? or any other way to create this form.
My need:
(in below image black area is transparent)
But now show my form like below image:-
Please let me know appropriate way.
You can't draw outside of your application, without using Adorners or Popups, as Akku says in the comments.
But what you can do is to, instead of making margins negative, make them positive. So that your content (the gradient background), have a margin of 10 or 20 (or whatever number that produces the right amount of spacing.
<Window (.....) AllowsTransparency="True" WindowStyle="None">
<Grid>
<Button VerticalAlignment="Top" HorizontalAlignment="Right" Height="15" Width="15"/>
<Border Margin="15">
<YOUR_CONTENT>
</Border>
</Grid>
</Window>

Control the width of child in Stackpanel

I'm trying to implement a certain layout.
I have two elements that I want to stack vertically (I need them to follow each other closely). I am currently trying to achieve it using a Stackpanel.
The problem is that I want the first element to have a limited width and the other to use all the width available in the StackPanel. Ideally, I would like that the first element have a width equals to the width of four columns from the grid that contains the StackPanel, here is my code.
<Grid>
<!-- Colums and Rows definition go here -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="4" Grid.Row="3" Grid.RowSpan="8">
//The first element
<Viewbox Name="viewbox_choix" Margin="160,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="0" Grid.ColumnSpan="4" Grid.Row="3" Grid.RowSpan="4">
//The second element
<StackPanel Grid.Column="0" Grid.ColumnSpan="5">
<Border></Border>
etc...
</StackPanel>
</StackPanel>
</Grid>
The grid attributes are referring to the parent grid of the stackpanel. But the Grid.Column and Grid.ColumnSpans seem to have no effect when I try to use them inside the StackPanel.
The problem of that code is that the first element also uses all the width of the StackPanel but that isn't what I want...
Can anybody help me ? I precise that I'm still learning WPF and I don't really know how bindings work...
In WPF, a StackPanel does not work like a Grid. There is no maximum width... it will happily let content disappear out of its right side. If you want automatic resizing, just replace the StackPanels with `Grid
UPDATE >>>
In the Grid class, there is an attached property called IsSharedSizeScope. Add this to the parent Grid and set it to true. Then in your RowDefinitions, you can add SharedSizeGroup properties to the columns that you require.
These examples may help you:
Grid's SharedSizeGroup and * sizing (SO post)
Grid.IsSharedSizeScope Attached Property (MSDN)
You may need to experiment a bit, but you should be able to get the desired effect using these properties.

How to use ScrollViewer.ScrollToVerticalOffset?

I hope this isn't a duplicate but I can't find any documentation or examples on how to actually use ScrollToVerticalOffset(). I'm using it in a Windows Phone 8 app, but I think it will still apply to WP7 and Silverlight (although, feel free to correct me if I'm wrong).
So here is my basic set up (pseudo-code from memory):
<phone.PivotItem>
<ScrollViewer>
<Grid Height="1500">
<Grid.RowDefinitions>
<!-- about 20 rows, all auto-height -->
</Grid.RowDefinitions>
<Border Grid.Row="0">
<TextBox x:Name="txt1" />
</Border>
<Border Grid.Row="1">
<TextBox x:Name="txt2" />
</Border>
<!-- ...... -->
<Border Grid.Row="19">
<TextBox x:Name="txt20" />
</Border>
</Grid>
</ScrollViewer>
</phone.PivotItem>
So as you can see, I've got a ScrollViewer within a PivotItem, and inside is a Grid. In the Grid there are about 20 TextBoxs, each within a Border. I am dynamically setting focus to one of these TextBoxs when this page loads, so anytime I set focus to TextBox #6-20 (roughly) - I have to manually scroll down to see it. I want to auto-scroll my ScrollViewer so that whichever TextBox has focus, it will be centered for the user to see.
The documentation for ScrollToVerticalOffset() says:
Scrolls the content that is within the ScrollViewer to the specified
vertical offset position.
And that it accepts a type of System.Double.
What I don't understand is A) the value I'm supposed to pass, and B) how I could even get that value? Is it supposed to be a number between 0 and the height of my Grid (1500)? If so, how could I determine the position of any given TextBox so I can scroll to it?
If there are any straightforward examples, please feel free to link out to them. I'm not sure if the content within the ScrollViewer matters when calling this method, but in case it does I wanted to show exactly how I'm using it.
Many thanks in advance!
You can see any UIElement's position relative to another UIElement using the UIElement.TransformToVisual call.
First, get the transform between the TextBox and ScrollViewer.
GeneralTransform transform = textBox.TransformToVisual(scrollViewer);
Then, figure out what point (0,0) of the TextBox is relative to the ScrollViewer. Meaning, the TextBox origin (0,0) is located at what ScrollViewer position.
Point textBoxPosition = transform.Transform(new Point(0, 0));
Now that you know the Y position of the TextBox relative to the ScrollViewer, scroll to that Y offset.
scrollViewer.ScrollToVerticalOffset(textBoxPosition.Y);
Good luck!
This is a very old post, but the meaning of VerticalOffset varies.
Most of the solutions I have seen assume VeritcalOffset is in pixels. This is not always the case.
From: https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.scrollviewer.extentheight
If CanContentScroll is true, the values of the ExtentHeight, ScrollableHeight,
ViewportHeight, and VerticalOffset properties are number of items. If
CanContentScroll is false, the values of these properties are Device Independent Pixels.

Adding buttons over windows border

How can I be able to place buttons over windows border.What I am trying to do is to place close and minimize buttons over the border in a WPF application in c#.Any one could please tell me how to do that.
The word 'Border' in the context of WPF may have two meanings. It may be the <Border> element, or it is possible you mean the area the defines the <Window> element. Which one is it?
If you just want to have a buttons on a <Border> element, just put it as the content of the element. If you have more than one buttons, you need to have a panel (e.g. <StackPanel>).
You cannot draw anything beyond the client area of a <Window> element. To have buttons outside the Window area, you should another Window (say 'toolwindow') with the buttons that you want. Most likely you want this toolwindow without caption and non resizable border: WindowStyle="None" ResizeMode="NoResize". Then, keep the tool window position in sync with your main window (best thing would be to bind the Left and Right properties of both Windows to Left and Right properties in a common data context. Don't forget to declare the Binding mode to BothWay).
EDIT (follow clarification from #Sarita):
So it is the first. By Content I meant the body of the XML element. Technically, it is the Child property of the Border element. The following two XAMLs are equivalent:
<Border Background="Green" Padding="5">
<StackPanel>
<Button>A</Button>
<Button>B</Button>
</StackPanel>
</Border>
<Border x:Name="Bord" Background="Green" Padding="5">
<Border.Child>
<StackPanel>
<Button>A</Button>
<Button>B</Button>
</StackPanel>
</Border.Child>
</Border>

Resources