Windows 8 App: "Snapping" Drag and Drop for Card Game - c#

After trying to use the following snippet to move cards (Images right now) around I was not satisfied with the result.
Card.ManipulationDelta += (o, args) => {
var dragableItem = o as Image;
if (dragableItem == null) return;
var translateTransform = dragableItem.RenderTransform as TranslateTransform;
if (translateTransform == null) return;
translateTransform.X += args.Delta.Translation.X;
translateTransform.Y += args.Delta.Translation.Y;
};
Card.RenderTransform = new TranslateTransform();
The control had a funny behavior to be accelerated and would move / slide a bit after "dropping" it. Although cool I do not want this behavior and therefore changed my mind: what I am looking for is a solution to define specific areas for one active card, a bench for a few more cards and stacks for the deck, such that one can freely drag one card but it can only be dropped if it is above these certain areas otherwise it will get back to the area designated for the hand cards.
What could I try to implement this desired behavior?

I think you and I are in the same boat, I'm working on a Metro card game application and I'm not relly happy with what I've found as far as Drag and Drop goes. My inital approach was going to be to have a grid \ stackpanel or other underlying framework that the user could drag a card image ( acually a custom control ) over and then the image would snap to that framework when the user let go. I have not yet found a suitable way to obtain this behavior however because it seems like drag-drop of controls from one parent to another is not supported in Metro.
As far as your question goes, the sliding effect that you are refering to is most likely intertia, You can disable this by not setting the TranslateInertia mode, for example
Ellipse el = new Ellipse();
el.Fill = new SolidColorBrush(Windows.UI.Colors.Magenta);
el.ManipulationMode = (ManipulationModes.All ^ MainipulationModes.TranslateInteria);
//more code to add your ManipulationDelta handler etc.
You can also gain some control over the Interia by adding a handler for MainipulationInertiaStarting, though just setting e.Handled = true in the handler does not disable interia entirely for me as others have suggested.
I'd love to hear back from you and see what approach you've come up with for snapping cards, at this point I'm considering just using a large Canvas object and writing my own customer handlers for mouse moved to get card objects to be draggable and then snap into a row or other location on the playing board.
Cheers,
James

Related

How to properly resize app to visible bounds on UWP? (VisibleBoundsMode doesn't seem to work)

I have two UWP apps and after testing them out with Continuum I noticed the app bar of the OS (the bar with the Start button) at the bottom of the screen (it can be at each of the 4 edges of the screen, of course) was covering part of my app.
Now, I'm already using ApplicationView.GetForCurrentView().SetDesiredBoundsMode(ApplicationViewBoundsMode.UseVisible) before calling Window.Current.Activate(), but that doesn't seem to solve the issue.
1) Why is it that setting the DesiredBoundsMode property doesn't seem to work here? Shouldn't that automatically resize the window
content to the visible bounds (ie. excluding system overlays like the
navigation bar or the app bar)?
The workaround I'm using for now on Windows 10 Mobile devices is to subscribe to the VisibleBoundsChanged event and then manually adjust the margins of my Window.Current.Content item to make sure it doesn't show anything behind covered areas of the screen.
Basically, I use the Window.Current.Bounds property and the ApplicationView.VisibleBounds property to calculate the occluded areas on the different edges of the app window, and increase the margins from there.
2) Is there a proper/better way to do this?
I mean, I'm quite sure there's another method that should be used to avoid this issue (considering there are tons of different situations like Continuum, navigation bar etc... that I don't think are supposed to be manually handled one by one).
Thank you for your help!
Use the subscription to the event VisibleBoundsChanged. This is the best solution that I found.
var curr = ApplicationView.GetForCurrentView();
if (curr.IsFullScreenMode == true)
{
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.FullScreen;
curr.FullScreenSystemOverlayMode = FullScreenSystemOverlayMode.Minimal;
}
else
{
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.Auto;
curr.FullScreenSystemOverlayMode = FullScreenSystemOverlayMode.Standard;
}

More than 2 millions rectangles in a WPF canvas

I am creating a custom control for semiconductor wafermap
Each of those small rectangle need to satisfy following requirements;
1) Tooltip to show the index
2) clickable to include or exclude from the wafermap definition.
no of dies in the wafermap may cross 2 millions in the case of 1400 x 1450 dies.
at certain point i need to show all the dies in a window (most of the clicking will happen in zoomed view).
Currently I am adding each die separately using Rectangle shape and store the coordinate information (index like (10,10)) for the tooltip as an attached property.
I use different style to each die; depending on certain calculation and position of the die.
DieStyle1 = new Style { TargetType = typeof(Rectangle) };
DieStyle1.Setters.Add(new Setter(Shape.FillProperty, Brushes.MediumSlateBlue));
DieStyle1.Setters.Add(new Setter(Shape.StrokeProperty, Brushes.White));
DieStyle1.Setters.Add(new EventSetter(MouseDownEvent, new MouseButtonEventHandler(DieStyle1_MouseDown)));
this approach is slow and use high memory too. so suggest a better way to achieve this in WPF?
In creating a designer for christmas tree lights, I ran into the same problem. Using UIElement or Shapes is way too slow when you get to 100+ items. The best approach to handle a very large number of items entails using double-buffering with your own managed buffer of the image and a structure to handle the clicks. I have posted my project which should give you a good start. It can be obtained at:
http://sourceforge.net/projects/xlightsdesigner/
You are interested in the Controls\ChannelitemsCanvas.cs. It can be modified to suit your needs and uses a quad-tree to store the rectangles so that click events can be quickly determined.

Overlaying a top-level window on top of another

In the software products I'm currently working on, we have several 3D View controls. Appeared the need to have overlay information on top of these 3D Views. I won't go into too much background details, because it is not the point, but here are the constraints we face :
we must use two different 3D View controls
we don't have the source code for them
they are embedded in Windows Forms controls, and all our own GUIs around these controls are in Windows Forms
we use .NET Framework 3.5SP1 and Windows 7
We want to be able to display various overlay informations and controls on top of these 3D views, because we usually demo our products by showing full screen 3D views on big screens, and not show our GUIs, which have the necessary information and controls.
Back in the days we used only one type of 3D view, I managed, via various hacks involving reflection, to hook my own overlay window system written in DirectX (based on WorldWind .NET overlay widgets, the 3D view was indeed based on WorldWind at the time). The next version of the 3D View product made huge changes to the rendering core code and of course made these hacks incompatible (yeah, I had it coming, I know :-)). Moreover, we are now using, because of different needs in other products, another type of 3D View, closed source as well.
I emphasize the fact that we don't have the source code for them because we can't have access to the rendering loop and therefore cannot hook a windowing system made for 3D Engines, such as CEGUI (search for it yourself, I'm not allowed to post much hyperlinks yet, sorry).
Consequently, I had the following idea : since our 3D Views are embedded in winforms controls, why don't we code our overlay controls in plain winforms, and overlay it on top of the 3D views? The advantages of this solution are huge :
this would be compatible with both 3D Views, enabling us to reuse overlays across engines, if needed
we would be able to reuse custom controls or forms we already developed for the rest of the GUI. Indeed, it is a pretty big project, and we are beginning to have quite a library of such controls.
The only slight (!) problem is that we want to be able to manage overlay transluency, like I did with my former system in DirectX. We can't afford fully opaque overlays, because it would clutter the view too much. Imagine something like a barely visible overlay, becoming more opaque when the mouse is hovering over it for example.
Windows offer the possibility to have child windows inside other windows or controls (Win32 API doesn't really make a difference between windows and controls, this is pretty much a MFC/WinForms abstraction as I understood it), but since it is not top-level windows, we cannot adjust the transluency of these, so this is not something we can use. I saw here, that this is however possible on Windows 8, but switching to windows 8 is not possible anytime soon, because our software is deployed on quite a few machines, running 7.
So I started an intense googling session on how could I work around such a problem. It appears I must "enslave" top level windows to my 3D View controls. I already tried out something like that directly in winforms, having a form owned (not parented, there is a clear distinction, read about it in the previously linked MS page) by a control, and "following" its movements on screen. As expected, it kind of worked, but the issues are difficult to overcome. The most important is a clipping issue. If the parent form of the owner control changes its size, the overlay form is still shown in full. In my sample, I have a simple form with a menu, and a black panel containing a calendar (to show clipping differences between child controls and owned ones). I "enslaved" a borderless form containing a property grid to the black panel. It successfully follows the forms movements, but if I shrink the main form, I get this :
Clipping issue screenshot
Note how the calendar is clipped correctly (child window), and the overlay is not (owned window). I also get weird effects when minimizing/restoring the main form. Indeed, my overlay disappears when minimizing, but when restoring, it just "spawns" while the restoring animation of the main form is occuring. But this is less of an issue, and I guess can be worked around by handling proper events (but which ones?).
From what I understood, I must handle at least some of the clipping myself, using win32 API calls and hooks. I already begun to document myself, but it is quite complicated stuff. The Win32 API being a real mess, and myself being a former Unix developer introduced to Windows programming via the great .NET framework, I don't have any real experience in Win32, and therefore don't really know where to begin, and how to make myself a path in this jungle...
So if a winapi guru is passing by, or if someone has some other idea to achieve my goals given the constraints above, I'll be glad to read about it :-)
Thanks in advance, and apologies for being such a stackoverflow "leecher" by subscribing only to ask a question, but I don't have no direct internet access on my workstation (yeah, for real, I have to go to a specific computer for this), so participating in this great community is not that easy for me.
Finally, here is my sample code (designer code available if you ask) :
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Point _myLoc;
private void formToolStripMenuItem_Click(object sender, EventArgs e)
{
var ctrl = new PropertyGrid();
var obj = this.panel1;
ctrl.SelectedObject = obj;
var form = new Form();
ctrl.Dock = DockStyle.Fill;
form.Controls.Add(ctrl);
form.Opacity = 0.7;
var rect = obj.RectangleToScreen(obj.DisplayRectangle);
form.StartPosition = FormStartPosition.Manual;
form.Location = new Point(rect.Left + 10, rect.Top + 10);
var parentForm = this;
_myLoc = parentForm.Location;
form.FormBorderStyle = FormBorderStyle.None;
parentForm.LocationChanged += (s, ee) => {
int deltaX = parentForm.Location.X - _myLoc.X;
int deltaY = parentForm.Location.Y - _myLoc.Y;
var loc = form.Location;
form.Location = new Point(loc.X + deltaX, loc.Y + deltaY);
_myLoc = parentForm.Location;
};
form.Show(this.panel1);
}
}
Clipping can be easily implemented using Region property. Each window can have an associated Region object, which defines window rendering constraints:
static void ManualClipping(Control clipRegionSource, Form formToClip)
{
var rect = clipRegionSource.DisplayRectangle;
rect = clipRegionSource.RectangleToScreen(rect);
rect = formToClip.RectangleToClient(rect);
rect = Rectangle.Intersect(rect, formToClip.ClientRectangle);
if(rect == formToClip.ClientRectangle)
{
formToClip.Region = null;
}
else
{
formToClip.Region = new Region(rect);
}
}
usage:
/* ... */
parentForm.SizeChanged += (s, ee) => ManualClipping(panel1, form);
form.Show(this.panel1);

Advice on Solitaire card game

I am busy with a 'home made' solitaire game just for fun but think however that I worked myself into a bit of a corner and was hoping for some advice perhaps.
In short instead dragging and dropping a card to a different location I click on the card to be moved (displayed in a picturebox) facing upwards and set the visiblity to false and add the cardvalue to an ArrayList(named picFaceUpToBeMoved).
I click on a second card and then of course based on certain conditions the card will be displayed just above the card I clicked now.I create an instance of the PictureBox control setting the size and location.
PictureBox picOneFaceUpA = new PictureBox();
picOneFaceUpA.Location = new Point(42, 202);
picOneFaceUpA.Width = 90;
picOneFaceUpA.Height = 120;
picOneFaceUpA.Image = Image.FromFile("../../Resources/" + picFaceUpToBeMoved[0] + ".png");
Controls.Add(picOneFaceUpA);
picOneFaceUpA.BringToFront();
The problem I have now is how to go about in moving this card as it doesn't have an onClick event.
Sorry, a bit inexperienced and was hoping for advice on how to overcome this issue or how I could approach this game differently.
Try adding an event handler to MouseClick.
More documentation can be found here: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.mouseclick.aspx
And have a look at all other events there are available, for dragging you could use MouseDown, MouseMove, MouseUp, etc.
A list of available events can be found here: http://msdn.microsoft.com/en-us/library/1dk48x94.aspx

Is there an easy way to make a ScrollViewer "bouncy"?

Im using a WPF ScrollViewer to host some controls. I'd really like it to interact like on a touch device where it slowly eases back into place when you pull it too far.
It doesn't have a scrollbar - I have manual mouse scrolling with click and drag using this code:
Point currentPoint = e.GetPosition(this);
// Determine the new amount to scroll.
Point delta = new Point(scrollStartPoint.X - currentPoint.X, scrollStartPoint.Y - currentPoint.Y);
if (Math.Abs(delta.X) < PixelsToMoveToBeConsideredScroll &&
Math.Abs(delta.Y) < PixelsToMoveToBeConsideredScroll)
return;
scrollTarget.X = scrollStartOffset.X + delta.X;
scrollTarget.Y = scrollStartOffset.Y + delta.Y;
// Scroll to the new position.
sv.ScrollToHorizontalOffset(scrollTarget.X);
sv.ScrollToVerticalOffset(scrollTarget.Y);
Is there an easy way to do this? Currently it just acts like a normal scrolling textbox and will neither pull outside its normal range, nor slowly ease back.
If you are working on a Touch device, look at the Microsoft SurfaceScrollViewer (http://msdn.microsoft.com/en-us/library/microsoft.surface.presentation.controls.surfacescrollviewer.aspx). It already has this behaviour built in.
Getting Touch interaction right is tricky, easier to find someone else who's already done it. ;-)

Categories