I have a list of buttons wrapped inside a stackpanel which stacks them horizontly. I want to know the code behind in C# to apply an animation such that if my mouse is near the left end of the MainWindow, the buttons slowly moves right. Whereas if my mouse is near the right side of the MainWindow, the buttons slowly moves left.
The buttons are added and styled at runtime.
If it is possible for you to use a canvas instead of the stackpanel you can use this code to achieve the animation I wrote for you right away:
Declare a field in you class like the following: private bool _running = true;
After this you can use this to animate your buttons.
new Thread(() =>
{
while (_running)
{
Thread.Sleep(20);
canvas.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
var position = Mouse.GetPosition(canvas).X;
var canvasWidth = canvas.ActualWidth;
if (position >=0 && position < 10.0d)
btn.SetValue(Canvas.LeftProperty, (double)btn.GetValue(Canvas.LeftProperty) + 1);
if (position <= canvasWidth && position > canvasWidth - 10.0d)
btn.SetValue(Canvas.LeftProperty, (double)btn.GetValue(Canvas.LeftProperty) - 1);
}));
}
}).Start();
Dont forget to add following usages to your class:
using System.Threading;
using System.Windows.Threading;
If you want the code to work with more than just one buttons just use a list for example and rewrite the code a little bit. Also adjust Thread.Sleep(20) to your needs.
Good luck.
Related
I am writing a battleship game in WPF C# where I hit on an enemy grid and if the opacity is an arbitrary value that signifies a ship placed there it will hit that board square. I have a function but it says displays the message that I win right on the first time that I hit a ship. I need for it to check if the whole board meets the requirement. This is the function
private void checkOurWin()
{
for (int i = 0; i < gridEnemy.Children.Count; i++)
{
if (((Button)gridEnemy.Children[i]).Background == Brushes.Red && ((Button)gridEnemy.Children[i]).Opacity == 1.00001)
{
MessageBox.Show("You have won congratulations!");
}
}
}
I am looping over all the children of the grid here and checking if the background has been already uncovered with a certain opacity but how do I do it for the entire grid and not just one item? Thanks!
You may use LINQ:
using System.Linq;
...
private void CheckOurWin()
{
if (gridEnemy.Children
.OfType<Button>()
.All(b => b.Background == Brushes.Red && b.Opacity > 1d))
{
MessageBox.Show("You have won congratulations!");
}
}
As a note, you should not be using UI element properties to store additional state data, like setting Opacity greater than 1.0. Use additional data fields in the MainWindow class (or even better, a view model class) or at least use the Buttons' Tag property.
Also note that a floating point comparison like Opacity == 1.00001 is inherently unsafe due to the way floating point values are stored. Such comparisons should generally be avoided.
I know that there are lot of different threads about horizontal text animation/text scrolling, but unfortunately none of them give smooth scrolling with repeatable text. I have tried double/thickness animation using various WPF controls containing text. Also tried animating with visual brush which gives me by far the most elegant scrolling compared to other approaches (for e.g. playing with Canvas.Left property etc.) but that too goes blur the text, if the text length or the animation speed is too high.
I'm over to a pure DirectX C# implementation using SharpDX library. Should also mention that I'm a beginner with DirectX programming. Here is the code:
public void RunMethod()
{
// Make window active and hide mouse cursor.
window.PointerCursor = null;
window.Activate();
var str = "This is an example of a moving TextLayout object with no snapped pixel boundaries.";
// Infinite loop to prevent the application from exiting.
while (true)
{
// Dispatch all pending events in the queue.
window.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessAllIfPresent);
// Quit if the users presses Escape key.
if (window.GetAsyncKeyState(VirtualKey.Escape) == CoreVirtualKeyStates.Down)
{
return;
}
// Set the Direct2D drawing target.
d2dContext.Target = d2dTarget;
// Clear the target.
d2dContext.BeginDraw();
d2dContext.Clear(Color.CornflowerBlue);
//float layoutXOffset = 0;
float layoutXOffset = layoutX;
// Create the DirectWrite factory objet.
SharpDX.DirectWrite.Factory fontFactory = new SharpDX.DirectWrite.Factory();
// Create a TextFormat object that will use the Segoe UI font with a size of 24 DIPs.
textFormat = new TextFormat(fontFactory, "Verdana", 100.0f);
textLayout2 = new TextLayout(fontFactory, str, textFormat, 2000.0f, 100.0f);
// Draw moving text without pixel snapping, thus giving a smoother movement.
// d2dContext.FillRectangle(new RectangleF(layoutXOffset, 1000, 1000, 100), backgroundBrush);
d2dContext.DrawTextLayout(new Vector2(layoutXOffset, 0), textLayout2, textBrush, DrawTextOptions.NoSnap);
d2dContext.EndDraw();
//var character = str.Substring(0, 1);
//str = str.Remove(0, 1);
//str += character;
layoutX -= 3.0f;
if (layoutX <= -1000)
{
layoutX = 0;
}
// Present the current buffer to the screen.
swapChain.Present(1, PresentFlags.None);
}
}
Basically it creates an endless loop and subtracts the horizontal offset. Here are the challenges: I need repeatable text similar to HTML marquee without any gaps, Would probably need to extend it to multiple monitors.
Please suggest.
I don't know neither how to use DirectX nor sharpdx, but if you want you can consider this solution
I had a similar problem a while ago, but with the text inside a combobox. After a bounty i got what i was looking for. I'm posting the relevant piece of code as an example, but you can check the complete answer here
Basically, whenever you have a textblock/textbox that contain a string that cannot be displayed completely, cause the length exceed the textblock/box lenght you can use this kind of approach. You can define a custom usercontrol derived from the base you need (e.g. SlidingComboBox : Combobox) and define an animation for you storyboard like the following
_animation = new DoubleAnimation()
{
From = 0,
RepeatBehavior = SlideForever ? RepeatBehavior.Forever : new RepeatBehavior(1), //repeat only if slide-forever is true
AutoReverse = SlideForever
};
In my example i wanted this behaviour to be active only when the mouse was on the combobox, so in my custom OnMouse enter i had this piece of code
if (_parent.ActualWidth < textBlock.ActualWidth)
{
_animation.Duration = TimeSpan.FromMilliseconds(((int)textBlock.Text?.Length * 100));
_animation.To = _parent.ActualWidth - textBlock.ActualWidth;
_storyBoard.Begin(textBlock);
}
Where _parent represent the container of the selected item. After a check on the text lenght vs combobox lenght i start the animation and end it at the end of the text to be displayed
Note that in the question i mentioned there are also other soltions. I'm posting the one that worked for me
I am Trying to make a GUI for HTC VIVE but having trouble in opening it on certain controller angle.
I have done some work and achieved a bit sketchy one because my object is a child which make it hard for me to track its rotation or position, as i wanted it to open only when controller is at certain angle (as a guy looking at his watch)
Here is some visual Example:
This is my controller rotation without GUI:
As i rotate the controller the GUI should show something like this:
Here is some code I have managed
void RayCastFromHead() // is just a name for Method i am raycasting from a dummy which contains left Grip button
{
if (Physics.Raycast(dummy.position, dummy.up, out hitInfo, 30))
{
transform.rotation.ToAngleAxis(out tempAngle, out tempAxis);
if (hitInfo.collider.name.Contains("Camera (eye)"))
{
if (dummy.gameObject.GetComponent<MeshRenderer>().enabled)
{
if ((transform.localEulerAngles.z > 270.0f && transform.localEulerAngles.z < 315.0f)&&
(transform.position.y > 0.9f && transform.position.y < 2f))
{
staticRotaion = transform.localRotation;
canvasOnHead.GetComponent<TweenScale>().PlayForward();
}
}
}
}
}
I do not know that it is a right method to do this kind of task? In Simple manner i want to show GUI on certain controller rotation.
This is My hierarchy what i am talking about
This is the same i wanna do with my GUI it should open when my hand angle is something like this image
There is a simple solution to handle UI rotation.
I suppose you have a canvas for your GUI. This canvas can be child of any object. If you add the canvas (root of this menu) as a child of the left hand it should move and rotate with the left hand.
Note that the render mode of the canvas must be World Space.
This is the parent (left hand):
set the values of canvas's rect transform correctly (most important part is pos.z, I changed the scale of the canvas instead of changing the z. I could change width and height of canvas but it would have adverse effects)
it will behave as you described when rotating the parent object (left hand):
Edit
Add this script to your camera
public class LookAtWatchController : MonoBehaviour
{
public GameObject menuGUI;
public GameObject hand;
void Update(){
if(transform.eulerAngles.x > 10)
{
menuGUI.transform.eulerAngles = new Vector3(transform.eulerAngles.x, 0, 0);
menuGUI.SetActive(true);
menuGUI.transform.position = hand.transform.position;
}
else{
menuGUI.SetActive(false);
}
}
}
assign the gui menu to menuGUI
assign the left hand to hand
you can also include the rotation elements of the hand in the menuGUI rotation:
menuGUI.transform.eulerAngles = new Vector3(transform.eulerAngles.x, hand.transform.eulerAngles.y, hand.transform.eulerAngles.z);
I haven't tested this yet but menuGUI.transform.eulerAngles = new Vector3(transform.eulerAngles.x, 0, 0); should also work fine.
As you see below the rotation.eulerAngles.x of camera and canvas are the same when canvas is seen right in front of camera
I have a C# webforms page where I want to drag html elements into a telerik radeditor. This part is working as expected except that when you drag an element onto the editor I want the cursor position in the radeditor to follow the mouse. It is set up similar to this demo on Teleriks web site. Except I am using a listview instead of treeview.
http://demos.telerik.com/aspnet-ajax/editor/examples/treeviewandeditor/defaultcs.aspx
I have tried simulating clicks on the radeditor to move the cursor, but no luck there. Any ideas?
Edit:
I have made a semi-working solution last week. Its far from perfect but I decided to share it in case some one else wants to make it better.
function controlDragging(sender, args) {
var event = args.get_domEvent();
var editor = $find("radEditLayout");
if (isMouseOverEditor(editor, event)) {
var x = event.pageX - event.offsetX;
var y = event.pageY - event.offsetY;
var node = editor.get_document().elementFromPoint(x, y);
if (node) {
setCaret(editor, node, 0);
}
}
}
function setCaret(editor, element, position) {
var selection = editor.getSelection(),
range = selection.getRange(true);
if (range.setStartAfter) {//W3 range
range.setStartAfter(element);
}
else { //IE7/8 textRange
range.moveToElementText(element);
range.moveStart('character', position);
}
range.collapse(true);
selection.selectRange(range);
}
function isMouseOverEditor(editor, event) {
return $telerik.isMouseOverElementEx(editor.get_contentAreaElement(), event);
}
Any more suggestions??
Perhaps you will be able to figure out something with ranges, but I am not sure exactly how as I have not used them. Here are the basics on getting an already selected range http://www.telerik.com/help/aspnet-ajax/editor-getselection-1.html and here is how to get the document object so you can use ranges in it: http://www.telerik.com/help/aspnet-ajax/editor-getting-reference-to-radeditor-documentobject.html. Perhaps this can help you get started but I think it will be a lot of work: How to set caret(cursor) position in contenteditable element (div)? because I am not sure how you can calculate the position at which you want the cursor from the mouse coordinates.
I know this post is old but perhaps others can benefit from it. Here's a snippet that helped me drop at a random position in the RadEditor content area. It does not involve moving the cursor position.
kendoDropTarget({
drop: function(e) {
debugger;
var top = e.draggable.drag.y.location - $('.k-content').offset().top;
var left= e.draggable.drag.x.location - $('.k-content').offset().left;
element.css({
top: top + 'px',
left: left + 'px'
});
$('.overlay').remove();
$('.k-content').contents().find('body').html($('.k-content').contents().find('body').html() + $(element).outerHTML());
}
I am using method SetView to zoom for two points in map but when they are too close I am too zoomed. So I hope I can check something like this:
myMap.SetView(bounds);
if (myMap.ZoomLevel > Constants.DefaultZoomLevel)
myMap.ZoomLevel = Constants.DefaultZoomLevel;
But method SetView isn't immediately set ZoomLevel property. What can I do to fix it? How can I set some zoom level border? Thanks
Edit:
I found that in 8.0 sdk there is ZoomLevelChanged event? This could be useful for me. So is there possible how to get it worked in 7.1?
I tried several solutions and these are my results (I needed working for WP7.1, with just targeting for WP8 there could be easier solution):
Use of TargetZoomLevel
Like this:
myMap.ZoomLevel = Math.Min(myMap.TargetZoomLevel, maxZoomLevel);
Doesn't solve my problem because SetView set ZoomLevel after this code execute. Map was just blinking between ZoomLevel from SetView and maxZoomLevel (I have timer for checking positions so that is why it was blinking and isn't good for me).
Use of MapZoom event
Like this:
private void map1_MapZoom(object sender, Microsoft.Phone.Controls.Maps.MapZoomEventArgs e)
{
if (((Map)sender).ZoomLevel > maxZoomLevel)
{
e.Handled = true;
}
}
Problem: MapZoom event handler is not fired when SetView it's used.
Check distance and set ZoomLevel if distance is little:
public static double GetDistanceBetweenPoints(LatLon firstPoint, LatLon secondPoint)
{
var sCoord = new GeoCoordinate(firstPoint.Lat, firstPoint.Lon);
var eCoord = new GeoCoordinate(secondPoint.Lat, secondPoint.Lon);
return sCoord.GetDistanceTo(eCoord);
}
usage:
var distance = LocationHelper.GetDistanceBetweenPoints(carPosition, userPosition);
if (distance < MinMetersDistance)
myMap.ZoomLevel = maxZoomLevel;
Problem: Again blinking. Sometimes I set ZoomLevel by this code. Other time it was set by SetView.
My real solution:
I just check distance between two points like in previous dot. But this time if the distance was little I just create new points from the old ones and set them in new positions (latitude and longitude) which was in min distance (one on the left side I moved more to left and second on the right side I moved more to right). Then I used SetView on new points.