Determining which CustomPopupPlacement was used for WPF Popup - c#

I'm trying to figure out which of the passed in array of CustomPopupPlacement positions have been used when the popup actually renders. Is there any event to detect this?
This msdn thread from 2009 seems to be exactly my issue however there does not seem to be an answer for it.
http://social.msdn.microsoft.com/Forums/da/wpf/thread/4c6d216a-0011-4202-aa7e-2fccef3cc355
The marked answer seems invalid and my situation is exactly as the OP in the thread.
I'm going to have my popup with 4 paths and use a DP to toggle visibility on three paths to choose the correct arrow path being rendered.
So given we provide 4 placement options via the CustomPopupPlacementCallbackdelegate, Is there a way to detect which of the 4 positions the system finally chose after dealing with screen edge cases and the sorts.

A better way to find placement of the Popup.
This method requires a Child element to be present, but that's no problem considering the Grid that comes with a Popup element.
UIElement container = VisualTreeHelper.GetParent(this) as UIElement;
Point relativeLocation = this.Child.TranslatePoint(new Point(0, 0), container); //It HAS(!!!) to be this.Child
if (relativeLocation.Y < 0) //or use X for left and right
{
Console.WriteLine("TOP PLACEMENT!");
}
else
{
Console.WriteLine("BOTTOM PLACEMENT!");
}

I have a little hacky solution.
Save the custom points as fields in the derived TooTip class and override the OnOpened method.
protected override void OnOpened(RoutedEventArgs e)
{
base.OnOpened(e);
var p = this.TranslatePoint(new Point(0, 0), this.PlacementTarget);
var diff1 = this.first - p;
var diff2 = this.second - p;
if (Math.Abs(Math.Min(diff1.Length, diff2.Length) - diff1.Length) < 0.01)
{
// First Point
}
else
{
// Second Point
}
}
Better solutions are welcome

Related

How do I check if all the children of a grid meet a certain requirement?

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.

How to create a smooth animated text marquee?

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

Windows Phone - check if MapCore.SetView doesn't zoom too much

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.

How to Override Children.Add method of Canvas class in WPF

I already have a Custom Canvas class in which i have override the 'OnMoseDown' method.
But now i also want to override 'Children.Add' method.
But i didnt find any solution.
I want to get Child.ActualWidth when a child gets added to canvas.
Thanks.
I just found my answer by myself. Hope this may help someone on some day.
Just added a Add method in my Custom class
public void Add(UserControl element)
{
bool alreadyExist = false;
element.Uid = element.Name;
foreach (UIElement child in this.Children)
{
if (child.Uid == element.Uid)
{
alreadyExist = true;
this.BringToFront(child);
}
}
if (!alreadyExist)
{
this.Children.Add(element);
this.UpdateLayout();
double top = (this.ActualHeight - element.ActualHeight) / 2;
double left = (this.ActualWidth - element.ActualWidth) / 2;
Canvas.SetLeft(element, left);
Canvas.SetTop(element, top);
}
}
This will likely not work correctly. A child will get added before it's ActualWidth is set, as that property gets set during the layout phase.
Depending on your goals here, you may want to consider overriding MeasureOverride and ArrangeOverride instead, and making a custom layout panel instead of subclassing Canvas.

Weird shape resizing behavior in WPF

I am making a WPF application that will let the user draw and resize shapes.
The resizing part is done using adorners, and the shapes are my own classes derived from Shape.
For example I have a Polyline, and for each of it's points I am adorning a Thumb with a handler on it's DragDelta event:
void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
PolylineEx polyline = this.AdornedElement as PolylineEx;
ResizingThumb thumb = sender as ResizingThumb;
int index = (int)thumb.Tag;
Point newPoint = new Point(
polyline.Points[index].X + e.HorizontalChange,
polyline.Points[index].Y + e.VerticalChange);
Trace.WriteLine(String.Format("Arranging point {0}:{1},{2}", index, newPoint.X, newPoint.Y));
polyline.Points[index] = newPoint;
}
Well, the problem is that sometimes (often), dragging a thumb is not smooth at all. First I thought it was a performance issue, because of a new Point being created every time (and other things), but then I noticed that sometimes the point is set up at weird coordinates that have nothing to do with the position of the mouse.
I've also uploaded a sample project HERE, could someone who knows his way around wpf take a look and enlighten me of what is happening?
Also, if anyone thinks of a better way for doing this, any feedback would be highly appreciated.
Thank you.
Edit: HERE is a new link to the project files.
I'm ending up answering my own question :)
I think the problem was here:
protected override System.Windows.Media.Geometry DefiningGeometry
{
get
{
StreamGeometry geometry = new StreamGeometry();
using (StreamGeometryContext context = geometry.Open())
{
context.BeginFigure(Points[0], false, true);
foreach (Point pt in Points)
{
context.LineTo(pt, true, true);
}
geometry.Freeze();
return geometry;
}
}
}
I switched to using PathGeometry & LineSegments and it works fine now.

Categories