Binding Event to View Model, Rotation of Image - xaml

I want to have a Rotation of an Image, but I don't want to Code the Events inside the Codebehind but in the View Model.
By now everything works fine, BUT the code is in the CodeBehind...
(It's based on this tutorial)
I tried
XAML:
[...]
ManipulationDelta="{Binding RotateManipulationDelta}"
[...]
<RotateTransform x:Name="{Binding RotateTransform}" />
ViewModel:
private void RotateManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
// Alternatively, use Triangle Cosines Law.
// It uses just one trigonometric function (Acos), but you first need to calculate the lengths of all sides.
var x = this.RotateTransform.CenterX - e.Position.X;
var y = this.RotateTransform.CenterY - e.Position.Y;
double a1 = Math.Atan(y / x);
double a2 = Math.Atan((e.Delta.Translation.Y - y) / (x - e.Delta.Translation.X));
this.RotateTransform.Angle += a1 - a2;
}
But C# obviously doesn't know "RotateTransform" or the Method itself.
Is there a possibility to do so? I have no clue.
And please try to explain it as simple as possible. I just started with Windows Apps and XAML. :D
I hope you can help me.

You may want to look at something like this Storyboarded animations for visual states or this XAML animation.
I don't get why you want to do something like this... Can you give us more infos ? It will be much more easy to do it in C# than in XAML. The point of the code behind is to do that stuff.

Related

Return imageView rotation position and stop if at a particular position

hoping someone can help. I am creating an app whereby the user will touch a series of images to rotate them. What I am trying to do. Is highlight the image once the user has rotated to a particular position.
Is this possible? If, so any tips greatly appreciated.
edit - ok here's an example instead!
First, the simplest way, based off the code example you just posted:
r1c1.setOnClickListener {
r1c1.animate().apply{ duration = 100 rotationBy(270f) }.start()
}
So the issue here is that you want to highlight the view when it's rotated to, say 90 degrees, right? But it has an animation to complete first. You have three options really
do something like if (r1c1.rotation + 270f == 90) and highlight now, as the animation starts, which might look weird
do that check now, but use withEndAction to run the highlighting code if necessary
use withEndAction to do the checking and highlighting, after the anim has finished
the latter probably makes the most sense - after the animation finishes, check if its display state needs to change. That would be something like this:
r1c1.animate().setDuration(100).rotationBy(270f).withEndAction {
// need to do modulo so 720 == 360 == 0 etc
if (r1c1.rotation % 360 == TARGET_ROTATION) highlight(r1c1)
}.start()
I'm assuming you have some way of highlighting the ImageViews and you weren't asking for ways to do that!
Unfortunately, the problem here is that if the user taps the view in the middle of animating, it will cancel that animation and start a new one, including the rotationBy(270) from whatever rotation the view currently happens to be at. Double tap and you'll end up with a view at an angle, and it will almost never match a 90-degree value now! That's why it's easier to just hold the state, change it by fixed, valid amounts, and just tell the view what it should look like.
So instead, you'd have a value for the current rotation, update that, and use that for your highlighting checks:
# var stored outside the click listener - this is your source of truth
viewRotation += 270f
# using rotation instead of rotationBy - we're setting a specific value, not an offset
r1c1.animate().setDuration(100).rotation(viewRotation).withEndAction {
// checking our internal rotation state, not the view!
if (viewRotation % 360 == TARGET_ROTATION) highlight(r1c1)
}.start()
I'm not saying have a single rotation var hanging around like that - you could, but see the next bit - it's gonna get messy real quick if you have a lot of ImageViews to wrangle. But this is just to demonstrate the basic idea - you hold your own state value, you're in control of what it can be set to, and the View just reflects that state, not the other way around.
Ok, so organisation - I'm guessing from r1c1 that you have a grid of cells, all with the same general behaviour. That means a lot of repeat code, unless you try and generalise it and stick it in one place - like one click listener, that does the same thing, just on whichever view it was clicked on
(I know you said youre a beginner, and I don't like loading too many concepts on someone at once, but from what it sounds like you're doing this could get incredibly bloated and hard to work with real fast, so this is important!)
Basically, View.onClickListener's onClick function passes in the view that was clicked, as a parameter - basically so you can do what I've been saying, reuse the same click listener and just do different things depending on what was passed in. Instead of a lambda (the code in { }, basically a quick and dirty function you're using in one place) you could make a general click listener function that you set on all your ImageViews
fun spin(view: View) {
// we need to store and look up a rotation for each view, like in a Map
rotations[view] = rotations[view] + 270f
// no explicit references like r1c1 now, it's "whatever view was passed in"
view.animate().setDuration(100).rotation(rotations[view]).withEndAction {
// Probably need a different target rotation for each view too?
if (rotations[view] % 360 == targetRotations[view]) highlight(view)
}.start()
}
then your click listener setup would be like
r1c1.setOnClickListener { spin(it) }
or you can pass it as a function reference (this is already too long to explain, but this works in this situation, so you can use it if you want)
r1c1.setOnClickListener(::spin)
I'd recommend generating a list of all your ImageView cells when you look them up (there are a few ways to handle this kind of thing) but having a collection lets you do things like
allCells.forEach { it.setOnClickListener(::spin) }
and now that's all your click listeners set to the same function, and that function will handle whichever view was clicked and the state associated with it. Get the idea?
So your basic structure is something like
// maybe not vals depending on how you initialise things!
val rotations: MutableMap<View, Float>
val targetRotations: Map<View, Float>
val allCells: List<ImageView>
// or onCreateView or whatever
fun onCreate() {
...
allCells.forEach { it.setOnClickListener(::spin) }
}
fun spin(view: View) {
rotations[view] = rotations[view] + 270f
view.animate().setDuration(100).rotation(rotations[view]).withEndAction {
val highlightActive = rotations[view] % 360 == targetRotations[view]
highlight(view, highlightActive)
}.start()
}
fun highlight(view: View, enable: Boolean) {
// do highlighting on view if enable is true, otherwise turn it off
}
I didn't get into the whole "wrapper class for an ImageView holding all its state" thing, which would probably be a better way to go, but I didn't want to go too far and complicate things. This is already a silly length. I might do a quick answer on it just as a demonstration or whatever
The other answer is long enough as it is, but here's what I meant about encapsulating things
class RotatableImageView(val view: ImageView, startRotation: Rotation, val targetRotation: Rotation) {
private var rotation = startRotation.degrees
init {
view.rotation = rotation
view.setOnClickListener { spin() }
updateHighlight()
}
private fun spin() {
rotation += ROTATION_AMOUNT
view.animate().setDuration(100).rotation(rotation)
.withEndAction(::updateHighlight).start()
}
private fun updateHighlight() {
val highlightEnabled = (rotation % 360f) == targetRotation.degrees
// TODO: highlighting!
}
companion object {
const val ROTATION_AMOUNT = 90f
}
}
enum class Rotation(var degrees: Float) {
ROT_0(0f), ROT_90(90f), ROT_180(180f), ROT_270(270f);
companion object {
// just avoids creating a new array each time we call random()
private val rotations = values()
fun random() = rotations.random()
}
}
Basically instead of having a map of Views to current rotation values, a map of Views to target values etc, all that state for each View is just bundled up into an object instead. Everything's handled internally, all you need to do from the outside is find your ImageViews in the layout, and pass them into the RotatableImageView constructor. That sets up a click listener and handles highlighting its ImageView if necessary, you don't need to do anything else!
The enum is just an example of creating a type to represent valid values - when you create a RotatableImageView, you have to pass one of these in, and the only possible values are valid rotation amounts. You could give them default values too (which could be Rotation.random() if you wanted) so the constructor call can just be RotatableImageView(imageView)
(you could make more use of this kind of thing, like using it for the internal rotation amounts too, but in this case it's awkward because 0 is not the same as 360 when animating the view, and it might spin the wrong way - so you pretty much have to keep track of the actual rotation value you're setting on the view)
Just as a quick FYI (and this is why I was saying what you're doing could get unwieldy enough that it's worth learning some tricks), instead of doing findViewById on a ton of IDs, it can be easier to just find all the ImageViews - wrapping them in a layout with an ID (like maybe a GridLayout?) can make it easier to find the things you want
val cells = findViewById<ViewGroup>(R.id.grid).children.filterIsInstance<ImageView>()
then you can do things like
rotatables = cells.map { RotatableImageView(it) }
depends what you need to do, but that's one possible way. Basically if you find yourself repeating the same thing with minor changes, like the infomercials say, There Has To Be A Better Way!

Windows Phone 8.1 Action Center like page design

I am trying to move an object in a page form top to down on user finger movement using translate transform. we should see page contents as the bar goes down the page and sits at bottom.
Just like Action Center in windows phone 8.1.
Please let me know any ideas how we can design. Thanks.
Good question!
My first thought was to do something like this.
You could get the touch input location and then move a rectangle from the top of the screen and translate it down according to they Y Cord of the Touch Input.
EDIT:
Okay so here is what you can do.
Create a Canvas and position it somewhere at the top ( i gave it the height of 14 in collapsed state).
Then create a private void cn_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e) event and make it set the height of the Canvas. I also included a float i to later make it snap back or cover the entire screen if the user lets go during the pull-event.
private void cn_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
{
cn.Height += e.DeltaManipulation.Translation.Y;
i = (float)e.CumulativeManipulation.Translation.Y;
}
And thats it. You can also add this event to make it snap back or go cover the full screen when the user lets go.
private void cn_ManipulationCompleted(object sender, System.Windows.Input.ManipulationCompletedEventArgs e)
{
if(i < 100)
{
cn.Height = 14;
}
else
{
cn.Height = Application.Current.Host.Content.ActualHeight;
}
}
Of course you can add smoother animations so it slowly goes back into the collapsed view or fills the entire page.
I hope this helps!

How can I run 2 game objects in XNA, or change in real time the draw destination?

I'm new here!
I searched internet a lot for my question, but I didn't found anything - or I'm really thinking wrong.
I program on VB.NET since 2 years, and on XNA since 6 months. I built a game and an editor for the game, and they are running great.
The question i about my editor (for an RPG game), and I'll try to explain at my best.
I have a main form with menustrips on top and a big picturebox covering the entire form, a picbox that is binded to the Game1 object when it start with the command Run().
The Game1 object handles two classes, that are basically panels that it draws on the picbox of the main form: a tileset panel in the left down the tabpage, and a map panel on the right. This works perfectly.
The problem is when for the first time yesterday I tried to draw with XNA on a form. I have multiple forms to manage NPCs, equipment, conditions, events, variables, etc and in the event form, I have a tabpage that manages map teleport events. On this tabpage I have a list of maps and a picbox where I want to draw a small view of the selected map. For this, I created of course a minimap panel with it's own draw and update methods.
...but of course, the minimap appears on the main form on the normal map.
I tried to change in real time the DeviceWindowHandle, but I failed... apparently, it changes only during the Run()
I tried to create a new game object and binding him to the event teleport form, but in the moment of lunching the Run() of this object, the debugger stops saying that I cannot launch more that one game loop in a thread.
I can't believe that XNA doesn't let to draw multiple things on different forms... and I can not pause the main loop from the event form (which is called from the NPC form) to start the minimap loop!
I think that is something really easy that unfortunately I don't know...
I'm getting crazy and lost... what I can do?
Please help me, thanks!!
Here's an example of what I commented (Sorry it's in C# but I don't really write VB.Net. Translating it should be pretty straight forward though):
private MainGame mainGame;
private ToolboxGame toolbox1;
private ToolboxGame toolbox2;
// And this should be put in some Form Initialization method:
Task.Factory.StartNew(() => {
this.mainGame = new MainGame(imgEditorPictureBox.Handle)
this.mainGame.Run();
}
Task.Factory.StartNew(() => {
this.toolbox1 = new ToolboxGame(toolbox1PictureBox.Handle)
this.toolbox1.Run();
}
Task.Factory.StartNew(() => {
this.toolbox2 = new ToolboxGame(toolbox2PictureBox.Handle)
this.toolbox2.Run();
}
Something like that should do it. Obviously whenever you "move" variables from one "game" to another, keep in mind that they run on different threads, so anywhere you use it, you'll need to
lock (dummyObject)
{
// Use data
}
to make sure you're not accessing it in one game, while the other is trying to set it.
Locking in VB.Net: Is there a lock statement in VB.NET?
You'll obviously need to come up with some smart infrastructure to get this working smoothly, but since you've made a game and editor before, I'm sure this should not prove a humongous challenge.
All you want show to the player you need draw in the game window. You have one Game with one GraphicsDevice and by default all you draw will be rendered on the game window. But you can call GraphicsDevice.SetRenderTarget method to change render target. Call it with RenderTarget2D object as parameter and anithing you will draw after this will be rendered to that render target.
Next you need call GraphicsDevice.SetRenderTarget(null) to set game window as render target again.
There is my (uncompleted yet) custom GUI realization for XNA. I hope it can help you.
Update
class Game1 : Game
{
GraphicsDevice graphicsDevice;
SpriteBatch spriteBatch;
public RenderTarget2D MinimapRenderBuffer;
public RenderTarget2D AnotherRenderBuffer1;
public RenderTarget2D AnotherRenderBuffer2;
public EventHandler RenderBuffersUpdated;
void Initialize()
{
// Better initialize them only once, don't do it in Draw method
this.MinimapRenderBuffer = new RenderTarget2D(this.graphicsDevice, 100, 100); // any size you want
this.AnotherRenderBuffer1 = new RenderTarget2D(this.graphicsDevice, 50, 50);
this.AnotherRenderBuffer2 = new RenderTarget2D(this.graphicsDevice, 500, 500);
}
void Draw()
{
this.graphicsDevice.SetRenderTarget(this.MinimapRenderBuffer);
// draw minimap to MinimapRenderBuffer
this.graphicsDevice.SetRenderTarget(this.AnotherRenderBuffer1);
// draw whatewer to AnotherRenderBuffer1
this.graphicsDevice.SetRenderTarget(this.AnotherRenderBuffer2);
// draw whatewer to AnotherRenderBuffer2
this.graphicsDevice.SetRenderTarget(null);
// now draw to screen
if (this.RenderBuffersUpdated != null)
{
RenderBuffersUpdated(null, null);
}
}
}
And use rendertargets in your editor when event raised. And you can convert them to bitmaps.

Binding a ScrollViewer from ViewModel to View

I Build a scrollViewer and its elements in my ViewModel, and it's built into a property FrameworkElement PageElement I rebuild the pageElement every time some event happens, I want to bind the PageElement to a real scrollViewer in the View so that whenever I change pageElement, it draws itself in it's view.
Let me give you a little armchair advice. I don't know the details of your project but the details in your question make me draw a few conclusions.
First, to have your view model create UI elements is not wrong. But it is really unusual. It sounds like you might be missing the concept of data template or data template selector.
Using a data template allows you to have a rich presentation of data that is built as the individual record is generated and rendered in a repeater or in a single content control.
Using a data template selector allows you to have various different presentations of data that using code-behind logic will switch between based on data or other criteria.
Ref on templates: http://blog.jerrynixon.com/2012/08/windows-8-beauty-tip-using.html
Second, to have your UI be re-generated as the result of an event being raised sounds like a short path to performance problems.
Every time you manually create elements and add them to the visual tree, you put your app at risk of binding lag while the layout is re-rendered. Run your app on an ARM and I bet you may already see it. Then again, a simplistic UI may not suffer from this general rule of thumb.
Because I do not know the event, I cannot presume it is frequently occurring. However, if it is frequently occurring, then even a simplistic UI will suffer from this.
Now to answer your question
Sherif, there is no write-enabled property on a scrollviewer that will set the horizontal or vertical offset. The only way to set the offset of a scrollviewer is to call changeview().
var s = new ScrollViewer();
s.ChangeView(0, 100, 0);
You cannot bind to a method, so binding to something like this is a non-starter without some code-behind to read the desired offset and calling the method directly.
Something like this:
public sealed partial class MainPage : Page
{
MyViewModel _Vm = new MyViewModel();
ScrollViewer _S = new ScrollViewer();
public MainPage()
{
this.InitializeComponent();
this._Vm.PropertyChanged += (s, e) =>
{
if (e.PropertyName.Equals("Offset"))
_S.ChangeView(0, _Vm.Offset, 0);
};
}
}
public class MyViewModel : INotifyPropertyChanged
{
private int _Offset;
public int Offset
{
get { return _Offset; }
set
{
_Offset = value;
PropertyChanged(this, new PropertyChangedEventArgs("Offset"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
But let me caution you. The offset will need to be based on something. And those variables may change based on the window size, the font size, scaling from transforms, and lots of other factors. The code above will work most of the time, but it will possible fail frequently on other devices.
So, what to do? My recommendation is that you code this in your code-behind, monitoring for whatever scenario you feel would require a scroll, and simply programmatically scroll it from bode-behind. Beware, though, programmatically scrolling a scrollviewer could make your UI confusing to the user.
You know your app. You will have to choose.
Best of luck!

Zooming in and out in Grid, Images on WinRT (Metro style app)

I'm trying to implement something in my app, I need to show an image, and let the user pinch in and out of the images.
I think its possible using the ScrollViewer, but I couldnt get it to work, help?
I hate to oversimplify this, but the WinRT XAML ScrollViewer has gesture manipulation built in.
You can see what I mean here. This might not be what you want. But it's sure a simple approach and might fit a certain % of scenarios. Maybe even yours.
Controls that incorporate a ScrollViewer in compositing often set a value for ZoomMode in the default template and starting visual states, and it is this templated value that you will typically start with. Controls with a ScrollViewer as part of their composition typically use template binding such that setting the attached property at the level of the control will change the scroll behavior of the ScrollViewer part within the control. Otherwise, it may be necessary to replace the template in order to change the scroll behavior of a ScrollViewer part.
Check out Morten Nielsen's article on Building A Multi-Touch Photo Viewer Control. It's for Silverlight/Windows Phone, but if you just enable manipulations on the image and change a few types in manipulation events - it should work great.
A simple solution that might be enough for you is to just put the image in a ScrollViewer, although to see it working - you need a touch screen or run it in a simulator (use the pinch tool, then drag and scroll on the image to zoom in/out).
You can also zoom it with code:
<Grid
Background="{StaticResource ApplicationPageBackgroundBrush}">
<ScrollViewer
x:Name="myScrollViewer">
<Image
Source="/Assets/SplashScreen.png" />
</ScrollViewer>
</Grid>
.
public BlankPage()
{
this.InitializeComponent();
myScrollViewer.ZoomMode = ZoomMode.Enabled; // default
Test();
}
private async void Test()
{
while (true)
{
for (double x = 0; x < 2 * Math.PI; x += Math.PI / 30)
{
await Task.Delay(1000 / 30);
float factor = (float)(1.0 + Math.Sin(x) / 10);
myScrollViewer.ZoomToFactor(factor);
}
}
}