avoid reload arcgis map on android - android-studio

I am moving a point every so often, the problem is that to keep the point inside the map and not get lost as it moves, I have to reload the map. How could you avoid recharging it, since the movement occurs every two seconds and the map is reloaded every two seconds is too uncomfortable.
Here the code:
cont++;
final long EXECUTION_TIME = 2000;
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
int aux = 0;
#Override
public void run() {
GraphicsOverlay graphicsOverlay1 = new GraphicsOverlay();
Graphic g1 = new Graphic(getLatLong(aux), attributes, sms);
graphicsOverlay1.getGraphics().add(g1);
mMap.getGraphicsOverlays().add(graphicsOverlay1);
map = new ArcGISMap(basemapType, getLatLong(aux).getY(), getLatLong(aux).getX(), 17);
mMap.setMap(map); //Here is where the map is reloaded, some other way to avoid this burden
handler.postDelayed(this, EXECUTION_TIME);
}
)};

You must use the method: SetViewpointCenterAsync in your mMap and thus avoid loading the map when updating points on the map.
The code would look like this:
map = new ArcGISMap(basemapType, getLatLong(aux).getY(), getLatLong(aux).getX(), 17);
mMap.setMap(map);
cont++;
final long EXECUTION_TIME = 2000;
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
int aux = 0;
#Override
public void run() {
GraphicsOverlay graphicsOverlay1 = new GraphicsOverlay();
Graphic g1 = new Graphic(getLatLong(aux), attributes, sms);
graphicsOverlay1.getGraphics().add(g1);
mMap.getGraphicsOverlays().add(graphicsOverlay1);
mMap.setViewpointCenterAsync(new Point( getLatLong(aux).getX(), getLatLong(aux).getY(),SpatialReferences.getWgs84()),6000.0) ;
handler.postDelayed(this, EXECUTION_TIME); } )};

Related

How to make a loop rerun from onLongClick()?

Here is the code. If a View has been long clicked, I want this loop to rerun by making i = 0. But the if statement after setOnLongClickListener only gets executed once in the beginning and not after the view has been long clicked.
final hasLongClicked[] = {false};
for(int i = 0; i < mLLayout.getChildCount(); i++){
// tried declaring hasLongClicked[] here but no avail
View child = mLLayout.getChildAt(i);
child.setOnLongClickListener(new View.OnLongClickListener(){
#Override
public boolean onLongClick(View v) {
//Some stuff
hasLongClicked[0] = true;
return false;
}
});
if(hasLongClicked[0])
i = 0;
}
How do I do get through this? On a separate note, is this a good way to setOnLongClickListeners to all child views of a linear layout?
Help is much appreciated. Thank you
I solved it by making a function out of it and calling itself whenever the event has been handledas follows:
private void discardEvents(LinearLayout mLLayout) {
for(int i = 0; i < mLLayout.getChildCount(); i++){
View child = mLLayout.getChildAt(i);
child.setOnLongClickListener(new View.OnLongClickListener(){
#Override
public boolean onLongClick(View v) {
//Do your stuff
discardEvents(mLLayout);
return false;
}
});
}
}
Although I would like to know if this would cause any problems/ has hidden bugs.

JavaFX make bar chart changing bars with delay in UI Thread

I got JavaFX main thread, there I create new Thread that extends Task and sort and replace bars. Everyhing is good, but I want to make some delays(like 100ms) while replacing to show step by step sorting, maybe with animation. The problem is when I use Thread.sleep() or TranslateTransition() it just sum all delays miliseconds together in one big delay that happens before changing bars. How can I make delay that will work properly in UI thread?
In main class:
Sorting sorting = new Sorting();
sortThread = new Thread(sorting, "sort");
sortThread.start();
sortThread.join();
And my class Sorting extends Task
public class Sorting extends Task<Void> {
//some stuff here
#Override
protected Void call() throws Exception {
taskThread = new Thread(counter, "time");
taskThread.setDaemon(true);
taskThread.start();
int n = array_tmp.length;
int temp;
for (int i = 0; i < n; i++) {
for (int j = 1; j < (n - i); j++) {
if (array_tmp[j - 1] > array_tmp[j]) {
//replacing bars
Node n1 = barChart.getData().get(j-1).getData().get(0).getNode();
Node n2 = barChart.getData().get(j).getData().get(0).getNode();
double x1 = n1.getTranslateX() + ((barChart.getWidth()-69)/array_tmp.length);
double x2 = n2.getTranslateX() - ((barChart.getWidth()-69)/array_tmp.length);
n1.setTranslateX(x1);
n2.setTranslateX(x2);
barChart.getData().get(j-1).getData().get(0).setNode(n2);
barChart.getData().get(j).getData().get(0).setNode(n1);
temp = array_tmp[j - 1];
array_tmp[j - 1] = array_tmp[j];
array_tmp[j] = temp;
}
}
}
}
}
There are two basic rules to threading in JavaFX:
UI components (nodes) that are part of a scene graph that is actually displayed can only be accessed from the JavaFX application thread. Some other operations (such as creating a new Stage) are also subject to this rule.
Any long-running or blocking operation should be run on a background thread (i.e. not the JavaFX application thread). This is because the JavaFX application thread is the one needed to render the UI and respond to user interaction. Consequently, if you block the FX Application Thread, then the UI cannot be rendered and the application will become unresponsive until your operation completes.
The javafx.concurrent API provides facilities for managing code that can be run on background threads and executing callbacks on the FX application thread.
The javafx.animation API additionally provides classes that allow UI code to be executed on the JavaFX application thread at specific times. Note that the animation API avoids creating background threads at all.
So for your use case, if you want to animate the swapping of two bars in the bar chart, you can do so with the animation API. A general method that creates an animation that performs such a swap might look like this:
private <T> Animation createSwapAnimation(Data<?, T> first, Data<?, T> second) {
double firstX = first.getNode().getParent().localToScene(first.getNode().getBoundsInParent()).getMinX();
double secondX = first.getNode().getParent().localToScene(second.getNode().getBoundsInParent()).getMinX();
double firstStartTranslate = first.getNode().getTranslateX();
double secondStartTranslate = second.getNode().getTranslateX();
TranslateTransition firstTranslate = new TranslateTransition(Duration.millis(500), first.getNode());
firstTranslate.setByX(secondX - firstX);
TranslateTransition secondTranslate = new TranslateTransition(Duration.millis(500), second.getNode());
secondTranslate.setByX(firstX - secondX);
ParallelTransition translate = new ParallelTransition(firstTranslate, secondTranslate);
translate.statusProperty().addListener((obs, oldStatus, newStatus) -> {
if (oldStatus == Animation.Status.RUNNING) {
T temp = first.getYValue();
first.setYValue(second.getYValue());
second.setYValue(temp);
first.getNode().setTranslateX(firstStartTranslate);
second.getNode().setTranslateX(secondStartTranslate);
}
});
return translate;
}
The basic idea here is pretty simple: we measure the distance in the x-coordinates between the two nodes; make a note of their current translateX properties, and then create two transitions which move the nodes so they take each others positions. Those two transitions are executed in parallel. When the transitions are complete (indicated by the status of the transition changing from RUNNING to something else), the values in the chart are exchanged and the translateX properties reset to their previous values (the effect of these will cancel out visually, but now the chart data will reflect the fact that the two have been exchanged).
If you want to perform a sort algorithm which animates the exchanges in the sorting, pausing between each step of the algorithm, you can do this using a background thread (you may be able to do this with an animation too - but this seems simple enough and is perhaps more instructional).
The idea here is to create a Task whose call() method performs the sort algorithm, pausing at various points to allow the use to see what is happening. Because we are pausing (blocking), this cannot be run on the FX Application Thread, as the blocking would prevent the UI being updated until the entire process was complete.
Here is an implementation of a bubble sort (for simplicity). On each iteration of the sort, we:
highlight the two bars to be compared in green*
pause so the user can see that
if the values need to be exchanged:
get the animation defined above and run it*
pause again, and
reset the colors*.
Steps marked * in the above psuedocode change the UI, so they must be executed on the FX Application thread, so they need to be wrapped in a call to Platform.runLater(...), which causes the provided code to be executed on the FX Application Thread.
The last tricky part here (and this is unusually tricky) is that the animation, of course, takes some time to execute. So we must arrange for our background thread to wait until the animation is complete. We do this by creating a CountDownLatch with a count of 1. When the animation is complete, we count the latch down. Then after submitting the animation to Platform.runLater(..), our background thread just waits for the latch to count down before proceeding, by calling latch.await(). It is quite unusual for a background thread to need to wait for something to run on the FX Application Thread, but this is one technique to do that in a case where you do need it.
The implementation of the bubble sort thus looks like
private Task<Void> createSortingTask(Series<String, Number> series) {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
ObservableList<Data<String, Number>> data = series.getData();
for (int i = data.size() - 1; i >= 0; i--) {
for (int j = 0 ; j < i; j++) {
Data<String, Number> first = data.get(j);
Data<String, Number> second = data.get(j + 1);
Platform.runLater(() -> {
first.getNode().setStyle("-fx-background-color: green ;");
second.getNode().setStyle("-fx-background-color: green ;");
});
Thread.sleep(500);
if (first.getYValue().doubleValue() > second.getYValue().doubleValue()) {
CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(() -> {
Animation swap = createSwapAnimation(first, second);
swap.setOnFinished(e -> latch.countDown());
swap.play();
});
latch.await();
}
Thread.sleep(500);
Platform.runLater(() -> {
first.getNode().setStyle("");
second.getNode().setStyle("");
});
}
}
return null;
}
};
}
Here is a complete demo. Since the sort algorithm, with its pauses, is encapsulated as a Task, we can leverage its callbacks and state properties if we need. As an example, we disable the buttons before starting the task, and use the onSucceeded handler to enable them again when it completes. It would be easy to add a "cancel" option too.
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javafx.animation.Animation;
import javafx.animation.ParallelTransition;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Duration;
public class AnimatedBubbleSort extends Application {
private Random rng = new Random();
private ExecutorService exec = Executors.newCachedThreadPool(runnable -> {
Thread t = new Thread(runnable);
t.setDaemon(true);
return t;
});
#Override
public void start(Stage primaryStage) {
BarChart<String, Number> chart = new BarChart<>(new CategoryAxis(), new NumberAxis());
chart.setAnimated(false);
Series<String, Number> series = generateRandomIntegerSeries(10);
chart.getData().add(series);
Button sort = new Button("Sort");
Button reset = new Button("Reset");
reset.setOnAction(e -> chart.getData().set(0, generateRandomIntegerSeries(10)));
HBox buttons = new HBox(5, sort, reset);
buttons.setAlignment(Pos.CENTER);
buttons.setPadding(new Insets(5));
sort.setOnAction(e -> {
Task<Void> animateSortTask = createSortingTask(chart.getData().get(0));
buttons.setDisable(true);
animateSortTask.setOnSucceeded(event -> buttons.setDisable(false));
exec.submit(animateSortTask);
});
BorderPane root = new BorderPane(chart);
root.setBottom(buttons);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
private Task<Void> createSortingTask(Series<String, Number> series) {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
ObservableList<Data<String, Number>> data = series.getData();
for (int i = data.size() - 1; i >= 0; i--) {
for (int j = 0 ; j < i; j++) {
Data<String, Number> first = data.get(j);
Data<String, Number> second = data.get(j + 1);
Platform.runLater(() -> {
first.getNode().setStyle("-fx-background-color: green ;");
second.getNode().setStyle("-fx-background-color: green ;");
});
Thread.sleep(500);
if (first.getYValue().doubleValue() > second.getYValue().doubleValue()) {
CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(() -> {
Animation swap = createSwapAnimation(first, second);
swap.setOnFinished(e -> latch.countDown());
swap.play();
});
latch.await();
}
Thread.sleep(500);
Platform.runLater(() -> {
first.getNode().setStyle("");
second.getNode().setStyle("");
});
}
}
return null;
}
};
}
private <T> Animation createSwapAnimation(Data<?, T> first, Data<?, T> second) {
double firstX = first.getNode().getParent().localToScene(first.getNode().getBoundsInParent()).getMinX();
double secondX = first.getNode().getParent().localToScene(second.getNode().getBoundsInParent()).getMinX();
double firstStartTranslate = first.getNode().getTranslateX();
double secondStartTranslate = second.getNode().getTranslateX();
TranslateTransition firstTranslate = new TranslateTransition(Duration.millis(500), first.getNode());
firstTranslate.setByX(secondX - firstX);
TranslateTransition secondTranslate = new TranslateTransition(Duration.millis(500), second.getNode());
secondTranslate.setByX(firstX - secondX);
ParallelTransition translate = new ParallelTransition(firstTranslate, secondTranslate);
translate.statusProperty().addListener((obs, oldStatus, newStatus) -> {
if (oldStatus == Animation.Status.RUNNING) {
T temp = first.getYValue();
first.setYValue(second.getYValue());
second.setYValue(temp);
first.getNode().setTranslateX(firstStartTranslate);
second.getNode().setTranslateX(secondStartTranslate);
}
});
return translate;
}
private Series<String, Number> generateRandomIntegerSeries(int n) {
Series<String, Number> series = new Series<>();
for (int i = 1; i <= n; i++) {
series.getData().add(new Data<>(Integer.toString(i), rng.nextInt(90) + 10));
}
return series;
}
public static void main(String[] args) {
launch(args);
}
}

Wrong results when trying to get sizes of a pane with css-formattings

I came across a strange behaviour of JavaFX when i tried to obtain the bordersizes (bounds) of a pane that has some css-effects//formattings applied to it. In my application i have to lookup the exact sizes of different objects in order to connect them with lines (imagine some sort of UML-diagramm editor, the start and endpoints of the lines are the border coordinates of the objects).
Now to my problem: whenever i try to get the bordersizes of an object in the same method where this object is put on the scene graph, the result does not include any css attributes like padding, bordersize, strokes and so on. The exact result gets returned if the object already exists on the scene graph before i lookup the size. It seems to be that JavaFX has to wait for one rendering pass (16,7ms) to actually update the real bounds and sizes on an object. Is there any way to get the size of an object (especially those which extend Pane) in the same method as it is created? I don't really like the workaround with waiting for 16,7ms, because it creates some unwanted behaviour in my application.
The following code shows the problem. The size when creating the pane containing the rectangle does not equal the size when pressing the "show size" button.
public class SzenarioView extends GridPane
{
private Group paintingLayer;
public SzenarioView()
{
super();
paintingLayer = new Group();
paintingLayer.getStylesheets().add(TestStarter.class.getResource("ReprBox.css").toString());
Rectangle r1 = new Rectangle(0, 0, 1000, 1000);
r1.setFill(Color.AZURE);
paintingLayer.getChildren().add(r1);
Button b1 = new Button("Show Size");
b1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
for(Node n : paintingLayer.getChildren())
{
System.out.println("Border...");
System.out.println(getNodeBorderCoords(n, BorderTypes.RIGHT)[0]);
System.out.println(getNodeBorderCoords(n, BorderTypes.RIGHT)[1]);
System.out.println("End Border");
}
}
});
Button b2 = new Button("Add CCSBTN");
b2.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
BorderPane bp = new BorderPane();
bp.getStylesheets().add(TestStarter.class.getResource("ReprBox.css").toString());
Rectangle rcss = new Rectangle(50, 50);
bp.setTop(rcss);
bp.getStyleClass().add("my-box");
setObjectOnScreen(bp, 100, 100);
System.out.println(getNodeBorderCoords(bp, BorderTypes.RIGHT)[0]);
System.out.println(getNodeBorderCoords(bp, BorderTypes.RIGHT)[1]);
}
});
this.add(b1, 0, 0);
this.add(b2, 1, 0);
this.add(paintingLayer, 1, 1);
this.setMaxHeight(500);
this.setMaxWidth(700);
this.setHgap(10);
this.setVgap(10);
this.setPadding(new Insets(10, 10, 10, 10));
}
public void setObjectOnScreen(Node obj, double toX, double toY)
{
obj.setLayoutX(toX);
obj.setLayoutY(toY);
paintingLayer.getChildren().add(obj);
}
public double[] getNodeBorderCoords(Node n, BorderTypes type)
{
double x = 0;
double y = 0;
double bx = n.getBoundsInLocal().getWidth();
double by = n.getBoundsInLocal().getHeight();
switch (type)
{
case LEFT:
x = n.getLayoutX();
y = n.getLayoutY() + by / 2;
break;
case RIGHT:
x = n.getLayoutX() + bx ;
y = n.getLayoutY() + by / 2;
break;
case TOP:
x = n.getLayoutX() + bx / 2;
y = n.getLayoutY();
break;
case BOTTOM:
x = n.getLayoutX() + bx / 2;
y = n.getLayoutY() + by;
break;
}
double[] ret =
{ x, y, };
return ret;
}
}
The CSS-File
#CHARSET "ISO-8859-1";
.my-box {
-fx-border-color: rgb(255, 0, 0);
-fx-border-radius: 2;
-fx-padding: 1 1 1 1;
-fx-border-width: 5 5 5 5;
}
By the way, it doesn't matter if use getBoundsInLocal() or getBoundsInParent() .
UPDATE
Here are two workarounds that can be used:
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
Platform.runLater(new Runnable() {
#Override
public void run() {
System.out.println(getNodeBorderCoords(bp, BorderTypes.RIGHT)[0]);
System.out.println(getNodeBorderCoords(bp, BorderTypes.RIGHT)[1]);
}
});
}
});
t.start();
But delaying the call might cause some strange behaviour like i stated in my post. But i found another "solution" recently.
bp.snapshot(new SnapshotParameters(), new WritableImage(5, 5));
System.out.println(getNodeBorderCoords(bp, BorderTypes.RIGHT)[0]);
System.out.println(getNodeBorderCoords(bp, BorderTypes.RIGHT)[1]);
The snapshot() method applies all css effects (and all other layout work) on the node. After that, the returned values of the borders are correct.
There are 2 approaches:
You can use binding instead of static size call. It gives benefits of additional support for update after resize but adds a bit of listeners handling burden on FX enging.
Wrapping size reading logic into Platform.runLater() will put it later into event queue and should address premature size access issue.

One JTextField stores and updates text, the other doesn't

So, I made a class that takes arrays and calculates a value from them. I then decided (unknowingly) to incorporate it into a GUI interface. All went well until I noticed this strange error; one of the jtextfields (prarie) would not store text while the other (yard) does.
I looked around and found my problem similiar to mine on this site;
Updating text in a JTextField
But he had one that doesn't work at all, where I have one that works and one that doesn't.
The Code is here (it's a bit long, but most of it is GUI), so hold your breath!:
import java.awt.GridLayout;
import javax.swing.Box;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Window {
/**
* #param args
*/
private static int numb;
private static double micro, centi;
private static JTextField[] yard,prarie;
private static double[] charges,distances;
public static void main(String[] args)
{
//create a small dialog window to take in number of charged objects
JPanel startup = new JPanel();
JTextField many = new JTextField(5);
startup.add(many);
int result = JOptionPane.showConfirmDialog(null,startup , "Please Enter How Many Charged Objects are Being Evaluated", JOptionPane.OK_CANCEL_OPTION);
many.requestFocusInWindow();
//once ok is clicked, then the number input will be stored under 'numb'
//then proceed to inputFields
if (result == JOptionPane.OK_OPTION)
{
numb = Integer.parseInt(many.getText());
inputFields();
}
}
//this window opens the various JTextFields for input
public static void inputFields()
{
//top JTextFields
yard = new JTextField[numb];
JPanel chargePanel = new JPanel();
for(int x=0;x<numb;x++)
{
yard[x] =new JTextField(5);
chargePanel.add(new JLabel("Charge "+ Integer.toString(x+1)+":"));
chargePanel.add(yard[x]);
chargePanel.add(Box.createVerticalStrut(15)); // a spacer
}
//bottom JTextFields
prarie = new JTextField[numb-1];
JPanel meterPanel = new JPanel();
for(int x=0;x<numb-1;x++)
{
prarie[x]=new JTextField(5);
meterPanel.add(new JLabel("Meters "+ Integer.toString(x+1)+":"));
meterPanel.add(new JTextField(5));
meterPanel.add(Box.createVerticalStrut(15)); // a spacer
}
//JCheckBoxes
JCheckBox isMicro = new JCheckBox("Charges are in terms of microCoulombs");
JCheckBox isCm = new JCheckBox("Distances are in terms of centiMeters");
JPanel chechBox = new JPanel();
chechBox.add(isMicro);
chechBox.add(Box.createVerticalStrut(20));
chechBox.add(isCm);
//Paste them all together into one window
GridLayout gufi = new GridLayout(3,1);
JPanel host = new JPanel(gufi);
host.add(chargePanel);
host.add(meterPanel);
host.add(chechBox);
int result1 = JOptionPane.showConfirmDialog(null, host, "Please Enter Charge and Distance Values", JOptionPane.OK_CANCEL_OPTION);
//if ok is clicked, then go to 'printArr()' to print the JTextFields
//then go to assign the values from the JTextFields to private double arrays 'yard' and 'prarie'
if (result1 == JOptionPane.OK_OPTION)
{
micro = (isMicro.isSelected())? Math.pow(10, -6): 1;
centi = (isCm.isSelected())? .01: 1;
printArr();
assign();
}
}
//a makeshift method to print the value from the JTextFields
//to fix the problem of why prarie wouldn't store numbers
public static void printArr()
{
System.out.println("Charges are:");
for(int x=0;x<numb;x++)
System.out.print(yard[x].getText() + " ");
System.out.println("Distances are:");
for(int x=0;x<numb-1;x++)
System.out.print(prarie[x].getText() + " ");
}
//assigns values from JTextFields to the private double arrays 'yard' and 'prarie'
public static void assign()
{
try {
charges = new double[numb];
for(int x=0;x<numb;x++)
charges[x]=micro*Double.parseDouble(yard[x].getText().trim());
distances = new double[numb-1];
for(int x=0;x<numb-1;x++)
distances[x]=centi*Double.parseDouble(prarie[x].getText().trim());
} catch (NumberFormatException e) {
e.printStackTrace();
//inputFields();
}
calculate();
}
public static void calculate()
{
JPanel sample = new JPanel();
JTextField whichOne = new JTextField(5);
sample.add(whichOne);
int result = JOptionPane.showConfirmDialog(null,sample , "Please Enter Which Charged Object thy Wishs For", JOptionPane.OK_CANCEL_OPTION);
whichOne.requestFocusInWindow();
if (result == JOptionPane.OK_OPTION)
{
int target = Integer.parseInt(whichOne.getText());
}
}
}
Anyone who runs the code and takes the time to enter dummy values will see that 'yard' stores values while 'prarie' does not. Why is this?
*I'm pretty sure I'm overlooking obvious (as always).
Change:
meterPanel.add(new JTextField(5));
to:
meterPanel.add(prarie[x]);
in the for loop for the prarie textfields

How to make void other thread visit until the code block finished for windows phone animation

I am making a top notification animation, but I don't know how to make the animation synchronous until the animation finishes. Here is the code I have:
public Storyboard prepareShowStory(int count, NotificationControl notifyControl)
{
notifyControl.textBlock1.Text = "Got" + count.ToString() + "Message";
notifyControl.RenderTransform = new CompositeTransform();
Storyboard story = new Storyboard();
//From here until the annimation finish and remove LayoutRoot.Resources.Clear();
LayoutRoot.Resources.Add("unique_id", story);
story.Completed += (object sender, EventArgs e) =>
{
story.Stop();
story.Children.Clear();
App.ViewModel.myAction -= CompletedRefresh;
LayoutRoot.Resources.Clear();
//To here.
};
story.Begin();
DoubleAnimation animation;
animation = new DoubleAnimation();
animation.AutoReverse = true;
animation.From = -64;
animation.To = 60;
animation.Duration = new Duration(TimeSpan.FromMilliseconds(1600));
animation.EasingFunction = _EasingFunction;
Storyboard.SetTargetName(animation, notifyControl.Name);
Storyboard.SetTargetProperty(animation, new PropertyPath("(UIElement.RenderTransform).(CompositeTransform.TranslateY)"));
story.Children.Add(animation);
return story;
}
You could check the ResourceDictionary before adding to it.
if(!LayoutRoot.Resources.Contains("unique_id"))
LayoutRoot.Resources.Add("unique_id", story);

Resources