How to get the object reference of backstack pages - windows-phone-8

I am trying to save a list of backstack pages that are Tombstoned, so that when I navigate back to them, I can compare if they are present in this list. If yes, I'll restore its state.
Currently my code looks like this.
public partial class App : Application
{
public static List<PhoneApplicationPage> TombstonedPages = new List<PhoneApplicationPage>();
private void Application_Activated(object sender, ActivatedEventArgs e)
{
if(!e.IsApplicationInstancePreserved)
{
foreach (JournalEntry j in (Application.Current.RootVisual as PhoneApplicationFrame).BackStack)
{
TombstonedPages.Add(//What should i add here);
}
}
}
}
code in some PhoneApplicationPage
protected override void OnNavigatedTo(NavigationEventArgs e)
{
//checking tombstone
if(e.NavigationMode== NavigationMode.Back && App.TombstonedPages.Contains(this) )
{
//restore state and delete entry from App.TombstonedPages
}
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
if(e.NavigationMode != NavigationMode.Back)
{
//save state
}
}
But I am unable to get a reference of pages from backstack. How should I do this? Is there a different way to do this?

Related

Frame.GoBack minimizes the Application

public Constructor1()
{
this.NavigationCacheMode = NavigationCacheMode.Enabled;
}
....
public Constructor2()
{
this.NavigationCacheMode = NavigationCacheMode.Enabled;
HardwareButtons.BackPressed += this.MainPage_BackPressed;
}
private void MainPage_BackPressed(object sender, BackPressedEventArgs e)
{
if(this.Frame.CanGoBack)
{
this.Frame.GoBack();
}
}
After I use the BackButton on my Windows Phone my Application minimizes itself. I have to go to the Task Manager and click on it to bring it back up.
Any suggestions why Frame.GoBack minimizes the Application?
private void MainPage_BackPressed(object sender, BackPressedEventArgs e)
{
if(this.Frame.CanGoBack)
{
e.Handled = true;
this.Frame.GoBack();
}
}
e.Handled = true; was the problem.

WP8 - How can I make the background agent execution to wait before all ImageOpened events are fired to update live tile with custom images?

How can I make the background agent execution to wait before all ImageOpened() events are fired (3 in this case) in order to update secondary live tile with custom images?
Edit 1:
In the OnInvoke() method of the ScheduledAgent I am calling my own create tile data function implemented in a shared library which in turn subscribes to 3 ImageOpened() events as I am trying to create custom images for all live tile templates i.e. small, medium and wide.
Since these being asynchronous events I have no way to check if all the events have completed successfully so that I can call NotifyComplete() to notify the background agent that its job is now done. So sometimes the tile gets updated while most of the times it doesn't. Also I am using the same function to update the live tiles every time the app is launched so there is no problem with its implementation. I have also tried to take care of all the memory limitations with the ScheduledAgent by disposing Bitmaps and calling GC.Collect() forcefully.
Please help in any possible way to fix this problem.
Add a new class that lets you create custom events -
public class SaveImageCompleteEventArgs : EventArgs
{
public bool Success { get; set; }
public Exception Exception { get; set; }
public string ImageFileName { get; set; }
public SaveImageCompleteEventArgs(bool success, string fileName)
{
Success = success;
ImageFileName = fileName;
}
}
Initialize the events and required variables in the file you are updating the custom live tile from -
public static int countTile = 3;
public event EventHandler<SaveImageCompleteEventArgs> SaveMediumImageComplete;
public event EventHandler<SaveImageCompleteEventArgs> SaveWideImageComplete;
public event EventHandler<SaveImageCompleteEventArgs> SaveSmallImageComplete;
public event EventHandler<SaveImageCompleteEventArgs> SaveAllImagesComplete;
Fire the completion event in the ImageOpened() event handlers for all the tiles and check if the SaveAllImagesComplete event needs to be fired-
public void OnBackgroundBmpOpenedMedium(object sender, RoutedEventArgs e)
{
if (SaveMediumImageComplete != null)
{
countTile -= 1;
CheckIfAllImagesOpened();
SaveMediumImageComplete(this, new SaveImageCompleteEventArgs(true, mediumTileImageUriIronMan));
}
}
private void CheckIfAllImagesOpened()
{
if (countTile == 0)
{
if (SaveAllImagesComplete != null)
{
var args1 = new SaveImageCompleteEventArgs(true, "");
SaveAllImagesComplete(this, args1);
}
}
}
In the ScheduledAgent file -
public static ManualResetEvent evt;
public bool IsPaused { get { return !evt.WaitOne(0); } }
In the OnInvoke() function -
evt = new ManualResetEvent(false);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
//Initialize secondary tile here
if (secondaryTile != null)
{
/*
obj is a object of a helper file that contains all the
functions responsible for updating the custom live tile
Call the function that is responsible for initializing all the
tile image bitmpas and that subscribes to the ImageOpened events
*/
obj.SaveMediumImageComplete += async (s, args) =>
{
if (!IsPaused)
evt.Set();
};
obj.SaveWideImageComplete += async (s, args) =>
{
if (!IsPaused)
evt.Set();
};
obj.SaveSmallImageComplete += async (s, args) =>
{
if (!IsPaused)
evt.Set();
};
obj.SaveAllImagesComplete += async (s, args) =>
{
try
{
if (args.Success)
obj.UpdateTileIcon();
}
catch (Exception) { }
finally
{
if (!IsPaused)
evt.Set();
}
};
}
});
evt.WaitOne();
NotifyComplete();

caliburn winrt usercontrol and capturing custom event

I made my own slider as user control with some custom properties and one custom event. Everything works fine, but recently I start using Caliburn Micro, and I don't know how to capture my custom event.
Previously I used:
<my:RadialSlider x:Name="slider" WedgeAngle="270" ..... AngleChanged="slider_AngleChanged" />
and
public void slider_AngleChanged(object sender, ValueChangedEventArgs e)
{
.... something ....
}
Now, in Caliburn project I tried:
<my:RadialSlider x:Name="slider" WedgeAngle="270" ..... cal:Message.Attach="[Event AngleChanged] = [Action slider_AngleChanged($eventArgs)]" />
and in my ViewModel:
public void slider_AngleChanged(object sender, ValueChangedEventArgs e)
{
.... something ....
}
But, this doesn't work...
So, how to capture this event?
Slider UC code-behind:
public delegate void AngleChangedEventHandler(object sender, ValueChangedEventArgs e);
public sealed partial class RadialSlider : UserControl
{
public event AngleChangedEventHandler AngleChanged;
private void OnAngleChanged(ValueChangedEventArgs e)
{
if (AngleChanged != null)
AngleChanged(this, e);
}
public static readonly DependencyProperty WedgeAngleProperty = DependencyProperty.Register("WedgeAngle", typeof(double), typeof(RadialSlider), new PropertyMetadata((double)270, new PropertyChangedCallback(OnPropertyWedgeAngleChanged)));
public double WedgeAngle
{
get { return (double)this.GetValue(WedgeAngleProperty); }
set { this.SetValue(WedgeAngleProperty, value); }
}
private static void OnPropertyWedgeAngleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
(sender as RadialSlider).UpdateControls();
if (e.NewValue != e.OldValue)
{
(sender as RadialSlider).OnAngleChanged(new ValueChangedEventArgs((double)e.OldValue, (double)e.NewValue));
}
}
}
You need to use a routed event. This has to do with how events bubble up the visual tree and how Caliburn.Micro attaches itself to them. Standard events should be avoided on controls or UI widgets in any tech using Xaml as the loose out on some pretty funky features (bubble up / down).

JTree and dropdown options on right clicking nodes

I'm trying to use the JTree and implement different drop downs for all the parent nodes and the children nodes.
Here's what I've done:
pmTree.addMouseListener(new java.awt.event.MouseAdapter() {
#Override
public void mouseClicked(java.awt.event.MouseEvent evt) {
try {
if(evt.getButton() == evt.BUTTON1) {
}
else if (evt.getButton() == evt.BUTTON3) {
TreePopup(evt);
//pmTree.updateUI();
}
}catch (Exception e) {}
}
});
and PopupCode:
public void TreePopup(java.awt.event.MouseEvent evt) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) pmTree.getLastSelectedPathComponent();
popup = new JPopupMenu();
popup.setInvoker(pmTree);
PopupHandler handler = new PopupHandler(pmTree, popup);
if(node.getLevel() == 1)
{
popup.add(getMenuItem("Parent Node", handler));
}
else if(node.getLevel() == 2)
{
popup.add(getMenuItem("Child", handler));
}
}
and PopUpHandler:
public class PopupHandler extends javax.swing.JFrame implements ActionListener {
JPopupMenu popup;
Point loc;
public PopupHandler(JTree tree, JPopupMenu popup) {
//this.tree = NewJFrame.pmTree;
this.popup = popup;
tree.addMouseListener(ma);
}
and also the
public void actionPerformed(java.awt.event.ActionEvent evt)
for the Child or Parent node being clicked.
However, when I run the program, I get the SAME right click popups for both the child and parent node.
Sorry for the huge chunk of code. I've been stuck with it for 2 days and yet not successful.
Thanks!
Don't go as low-level as a MouseListener, instead use the api around componentPopupMenu. Doing so, the general approach is dynamically configure the componentPopup in the getPopupLocation method, some simple example snippet:
JPopupMenu popup = new JPopupMenu();
final Action action = new AbstractAction("empty") {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
};
popup.add(action);
JTree tree = new JTree() {
/**
* #inherited <p>
*/
#Override
public Point getPopupLocation(MouseEvent e) {
if (e != null) {
// here do your custom config, like f.i add/remove menu items based on context
// this example simply changes the action name
TreePath path = getClosestPathForLocation(e.getX(), e.getY());
action.putValue(Action.NAME, String.valueOf(path.getLastPathComponent()));
return e.getPoint();
}
action.putValue(Action.NAME, "no mouse");
return null;
}
};
tree.setComponentPopupMenu(popup);
You check the selected node:
DefaultMutableTreeNode node = (DefaultMutableTreeNode)pmTree.getLastSelectedPathComponent();
to see if you have a "parent" or a "child" node. You should select the node at the mouse position first, otherwise it will not be the right node. Call
TreePath path = pmTree.getPathForLocation(evt.getX(), evt.getY());
if (path != null) {
pmTree.setSelectionPath(path);
} else {
return;
}
at the beginning of treePopup. (methods in Java should start with a lower case letter!)
Awesome. I was successfully able to put the setSelectionPath() call inside the override of getPopupLocaiton(). I had been trying to do it inside the ActionListener of my JMenuItem to no avail.
public Point getPopupLocation( MouseEvent e ) {
Point point = null;
if( e != null ) {
TreePath path = getClosestPathForLocation( e.getX(), e.getY() );
setSelectionPath( path );
point = e.getPoint();
}
return point;
}

What is the best way to trigger a combo-box cell editor by typing in a JTable cell?

In other words, I want JTable to drop-down a combo-box whenever user types in a cell that has a JComboBox (or any other JComboBox-based cell-editor) editor associated to it.
Basically, you have to install an appropriate listener on the combo and open the popup explicitly. First candidate for "appropriate" is an AncestorListener, which invokes showing the popup in its ancestorAdded method.
Unfortunately that doesn't seem to be the whole story: works if the table's surrenderFocus property is false. If it is true works only for not-editable combos. After some digging, the reason for the not-working part turns out to be an internal focustransfer (from the combo to the textfield) after the popup is opened by the ancestorListener. In that case, we need a second listener which opens the popup once the editor's editingComponent got the focus permanently.
Multiple listeners routinely step onto each other's feet, so best to not install both permanently but do it on each call to getEditorComp, and let them uninstall themselves once they showed the popup. Below is a working example of how-to do it, just beware: it's not formally tested!
public static class DefaultCellEditorX extends DefaultCellEditor {
private AncestorListener ancestorListener;
private PropertyChangeListener focusPropertyListener;
public DefaultCellEditorX(JComboBox comboBox) {
super(comboBox);
}
/**
* Overridden to install an appriate listener which opens the
* popup when actually starting an edit.
*
* #inherited <p>
*/
#Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
super.getTableCellEditorComponent(table, value, isSelected, row, column);
installListener(table);
return getComponent();
}
/**
* Shows popup.
*/
protected void showPopup() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
getComponent().setPopupVisible(true);
}
});
}
/**
* Dynamically install self-uninstalling listener, depending on JComboBox
* and JTable state.
* #param table
*/
private void installListener(JTable table) {
if (getComponent().isEditable() && table.getSurrendersFocusOnKeystroke()) {
installKeyboardFocusListener();
} else {
installAncestorListener();
}
}
private void installAncestorListener() {
if (ancestorListener == null) {
ancestorListener = new AncestorListener() {
#Override
public void ancestorAdded(AncestorEvent event) {
getComponent().removeAncestorListener(ancestorListener);
showPopup();
}
#Override
public void ancestorRemoved(AncestorEvent event) {
}
#Override
public void ancestorMoved(AncestorEvent event) {
}
};
}
getComponent().addAncestorListener(ancestorListener);
}
private void installKeyboardFocusListener() {
if (focusPropertyListener == null) {
focusPropertyListener = new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
LOG.info("property: " + evt.getPropertyName());
if (focusManager().getPermanentFocusOwner() !=
getComponent().getEditor().getEditorComponent()) return;
focusManager()
.removePropertyChangeListener("permanentFocusOwner", focusPropertyListener);
showPopup();
}
};
}
focusManager().addPropertyChangeListener("permanentFocusOwner", focusPropertyListener);
}
/**
* Convience for less typing.
* #return
*/
protected KeyboardFocusManager focusManager() {
return KeyboardFocusManager.getCurrentKeyboardFocusManager();
}
/**
* Convenience for type cast.
* #inherited <p>
*/
#Override
public JComboBox getComponent() {
return (JComboBox) super.getComponent();
}
}
JTable table = new JTable(data, columns);
table.putClientProperty("terminateEditOnFocusLost", true);
JScrollPane scrollPane = new JScrollPane(table);
final JXComboBox editorComboBox = new JXComboBox(array);
editorComboBox.addAncestorListener(new AncestorListener() {
public void ancestorAdded(AncestorEvent event) {
//make sure combobox handles key events
editorComboBox.requestFocusInWindow();
}
public void ancestorMoved(AncestorEvent event) {}
public void ancestorRemoved(AncestorEvent event) {}
});
AutoCompleteDecorator.decorate(editorComboBox);
TableColumn column = table.getColumnModel().getColumn(0);
column.setCellEditor(new ComboBoxCellEditor(editorComboBox));