I'm building a wp7 app in Silverlight. All of my app's state is stored in NavigationContext.QueryString. If this could be saved on application deactivation, and that page navigated to on application reactivation, that would take care of my requirements for tombstoning.
However, I'm not quite sure how to do this. I was thinking about saving NavigationContext.QueryString to the State dictionary in App.xaml.cs::Application_Deactivated(), but that code doesn't have access to NavigationContext.QueryString. Is there another way I can do this?
I suppose I could just save the query string to the State dictionary every time I navigate, then restore that when the app is re-activated. Or is there a better approach?
Update: Based on indyfromoz's answer, I'd like to implement the following
OnNavigatedToHandler()
{
// save NavigationContext.QueryString in the State dictionary
}
To reduce redundancy, I thought I'd implement this in a class that inherits from PhoneApplicationPage, then have all the rest of my pages inherit from that class. However, I then get the problem that all the page classes are partial because they are also defined in generated code. I don't want to change the generated code, because rechanging it every time it gets regenerated would be a huge pain.
Is there a better way to do this?
Update 2: Here is what I am hacking together now in the main page of my app (the one that is navigated to on startup):
public partial class MainPivot : PhoneApplicationPage
{
public MainPivot()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPivot_Loaded);
PhoneApplicationService.Current.Deactivated += new EventHandler<DeactivatedEventArgs>(App_Deactivated);
MessageBox.Show("launching main pivot (state count: " + PhoneApplicationService.Current.State.Count + ")");
if (PhoneApplicationService.Current.State.Count != 0)
{
Debug.Assert(PhoneApplicationService.Current.State.ContainsKey(QueryStringKey),
"State is initialized, but contains no value for the query string");
string oldQueryString = (string)PhoneApplicationService.Current.State[QueryStringKey];
MessageBox.Show("Old query string: " + oldQueryString);
NavigationService.Navigate(new Uri(oldQueryString));
}
}
public readonly string QueryStringKey = "queryString";
void App_Deactivated(object sender, DeactivatedEventArgs e)
{
PhoneApplicationService.Current.State[QueryStringKey] = NavigationService.Source;
}
// ...
It works (sorta) but it's ugly.
Update 3: Looks like the wp7 OS will automatically reload the correct page in a page-based app. I am in fact using pages, so perhaps there's not that much work I need to do here.
However, it doesn't seem to be working. I launch the app, go to a page, hit "Start", then hit "Back". The screen says "Resuming..." but seems to hang there. Is my code supposed to be responding in some way at this point? Is there a way I can keep the debugger attached even after hitting "Start"?
Transient data is usually stored in the State dictionary provided by the PhoneApplicationService class. The data is stored in the OnNavigatedFrom event of the page and restored from the OnNavigatedTo event of the page. If you stored the parameters from the URI of the page in the state dictionary within the OnNavigatedFrom event that is available in every page of your application, you can implement the logic to read the parameters in the OnNavigatedTo event, thereby taking care of Tombstoning
HTH, indyfromoz
Related
I have a list of models that are displayed on the views. Say they are a list of Task. The list has a check button where one can check if Task is done. I want them to be updated on the database at once. How would I do that ?
Here's how my controller looks like :
public async Task<ActionResult> TaskManager(Tasks model, string id)
{
var user = await UserManager.FindByIdAsync(id);
var list = from task in context.Tasks.Where(t=> t.isAssigned == false)
select task;
foreach(var t in task)
{
t.isAssigned =(bool) // FROM EACH LIST ITEM IN THE VIEW ;
}
await context.SaveChangesAsync();
return View();
}
button where one can check if Task is done. I want them to be updated on the database at
once. How would I do that ?
You look at the wrong place. It isn not by doing "normal" MVC but by using Ajax.
User presses checkbox, a callback is made to a Api method (REST method) that does not return a HTML page but juts 200 - OK. It gets the ID as parameter and updates the task in the database. Right there, immediatly when the value changes.
Basically if you want to react to a checkbox change, you must do so - and it gets inefficient and slow to refresh the whole page then. This is why Microsoft invented many many year ago Ajax (before others even came up with the word). And it is well supported.
This is the moment you have to byte the not totally sweet apple for some of us and learn some javascript / JQuery to run in the browser. Been there last week, it is not THAT hard ;)
Entity Framework is not supporting by default Batch processing. There are few possibilities for that. See this comment:
https://stackoverflow.com/a/13024320/1164761
I'm looking for a design approach, so I don't have any code to share.
I have a WPF rich-client application that presents detail data to the user. When the user clicks "Edit" The entire form goes into edit state. This reveals a couple of "Add" buttons. These "Add" buttons open child views providing the user with tools to create new entities. Think "adding a new item to a customer order you're working with". That's the easy part.
When the user closes these child views, the new entities must be displayed and editable in the parent view for continued detailed editing. Something like "add the new item on the child form, pick the part number, then close the child and add quantity and delivery date on the parent view. I don't have any flexibility in this workflow. I have this working also.
When the user is finished with the parent view and is satisfied with the newly added items and detail edits they can click "Save". That is when all the changes need to go back to the database. If the user clicks cancel, all the changes including entities created on the child views must disappear, and the form returned to it's original state.
It's that last bit that stumps me. I'm almost new to Entity Framework, so I thought I could somehow keep the entire set of changes in memory on the client and commit all the changes to the database at the point of user-Save. I don't know if that's possible, or how I have to impliment my data changes to prevent accidental trips to the database.
To put all the facts on the table, I'm using a unit of work pattern, but I have access to an EF context object, if needed. If I have to work with the context object, I must do so across several views and their associated view-models.
I've looked at a whole lot of stackoverflow Q&A but cannot find, or perhaps recognize, a solution path. I've some ideas about using cloned entities, or perhaps transactions, but do not know if there are others or how to choose between them. These would be new skills and require time spent learning. I am willing to spend time learning a new skill, but not learning and trying three or four.
I'm grateful for any advice you might offer.
On the constructor when read from the DB record the value twice. One private variable for current and one for Old.
private string lNameOld;
private string lName;
public string LName
{
get { return lName; }
set
{
if(lName == value) return;
lName = value;
NotifyPropertyChanged("LName");
}
}
public void save()
{
if (lName != lNameOld)
{
// write to database
// really should process all in a transaction
lNameOld = lName;
}
{
public void cancel()
{
if (lName != lNameOld)
{
Lname = lNameOld; // notice capital L so Notify is called
}
{
what is the best way to load dropdown lists from reference/lookup tables for a desktop application?
the application is layed out into 3 tiers. I've built up my entities.
the front end has a form with 6 tabs. and one big save (another discussion :)
Should I load them all when the form is initially loaded? Are there any caching mechanisms I could use?
it is vb.net app on a network drive that is accessed by several users.
it's also worth noting that some reference tables may be updated. Via another form.
thanks
T
Lots of factors. One you need to populate in constructor so the data is there to populate the visual elements. Beware that just because a tab is not visible does not mean it is not loaded when you app starts.
For a static list of strings
public class Library : INotifyPropertyChanged
{
private List<string> dropDown1;
public List<string> DropDown1 { get { return dropDown1; } }
public Library()
{
// use data reader to populate dropDown1
}
}
I know this will get comments that can use something lighter than a List but List has a lot of nice features, easy syntax, and easy to populate. As a next step you could structure as a client server and use some static so the list is populated once and then shared by all. If you have more properties then substitute string with a class. For a dynamic list then in the get you grab the current data from the table on demand. In your get you could hold on to the last list and if the next request is within X seconds then return stale data. It depends on if stale data is acceptable.
There are many other approaches and I do not pretend this is the best. Just putting out a relatively simple example to get you started.
When it gets to hierarchical then things get a little more complex. There you can use ADO.NET table to store the static dependent data and then apply a filter on a view.
If its a web page you don't have to load all tabs on page load.
Desktop i think it will be more easy and it should be like that.
Only when the user click on the tab show the page and hide all the pages
associated for other tabs.
i hope all tab pages values will be on session so that user can go and come back to any tab and your Big Save at last.
Something useful related to your question i found here
http://www.syncfusion.com/FAQ/windowsforms/faq_c93c.aspx
and one more
the title pretty much explains my issue:
I am right now taking care of drag & drop in my app. I can have many instances of my app running at the same time, and I can drag from one instance to the other without trouble.
Now, I would like to know if I'm drag & dropping "internally" (i.e: the drop occurs in the same instance as the drag) or "externally" (the opposite)
I went this far: I need to add to my dragged data a unique ID (something like a PUID) that identifies the app where I'm making the drag. Then I can just compare this id to the one I have locally on the drop and see if it is the same.
I have no problem transferring such info in my drag Data, the issue is more to find this UId.
I have been thinking using the Process.GetCurrentProcess().MainWindowHandle; but I'm not sure if this is a good idea.
What option(s) do I have to make this work?
I would simply create a readonly Guid that gets set when you start your app.
You can put this wherever your main logic lives (MainWindow or ViewModel).
Here is a snippet:
public class MyViewModel
{
private readonly Guid mUID = Guid.NewGuid();
// In case you want a property for it
public string UniqueApplicationID
{
get { return mUID; }
}
public void OnDropHandler(MyViewModel objectBeingDropped)
{
if (objectBeingDropped.UniqueApplicationID == mUID)
return;
// Handle drop normally here
}
}
The D-n-D is much like an UI activity, than an internal one.
I would distinguish two contexts: dropping a file, and dropping some object (e.g. VS designer). In the first context there's no problem at all, because it doesn't matter where you pull the data. In the second case, you should know what object has been chosen. For instance, you have a listbox with many items (e.g. the alphabet chars), once the user D-n-D any of those items, the internal operation is a simple reference to the selected object. By pulling the data from another app, you won't be able to find your object, because the source is different.
In case of structs or strings, you may wrap them with a GUID, as you correctly proposed.
In the context of a navigation-style WPF application (NavigationWindow, not XBAP):
Is it possible for a Hyperlink's NavigateUri to contain extra parameters, like path data or a querystring? E.g., is there some way I could set my NavigateUri to /Product.xaml/123 or /Product.xaml?id=123, and have my Product.xaml page be able to see that it was called with a parameter of 123?
You can do this. See http://www.paulstovell.com/wpf-navigation:
Although it's not obvious, you can
pass query string data to a page, and
extract it from the path. For example,
your hyperlink could pass a value in
the URI:
<TextBlock>
<Hyperlink NavigateUri="Page2.xaml?Message=Hello">Go to page 2</Hyperlink>
</TextBlock>
When the page is loaded, it can
extract the parameters via
NavigationService.CurrentSource, which
returns a Uri object. It can then
examine the Uri to pull apart the
values. However, I strongly recommend
against this approach except in the
most dire of circumstances.
A much better approach involves using
the overload for
NavigationService.Navigate that takes
an object for the parameter. You can
initialize the object yourself, for
example:
Customer selectedCustomer = (Customer)listBox.SelectedItem;
this.NavigationService.Navigate(new CustomerDetailsPage(selectedCustomer));
This assumes the page constructor
receives a Customer object as a
parameter. This allows you to pass
much richer information between pages,
and without having to parse strings.
Another way is to create a public variable on the destiny page and use a get/set property to assign a value to it.
On Page:
private Int32 pMyVar;
public Int32 MyVar
{
get { return this.pMyVar; }
set { this.pMyVar = value; }
}
When navigating to it:
MyPagePath.PageName NewPage = new MyPagePath.PageName();
NewPage.MyVar = 10;
this.MainFrameName.NavigationService.Navigate(NewPage);
When NewPage is loaded, the integer MyVar will be equal to 10.
MainFrameName is the frame you are using in case you are working with frame, but if not, the navigate command remains the same regardless.
Its my opinion, but it seems easier to track it that way, and more user friendly to those who came from C# before WPF.
Customer selectedCustomer = (Customer)listBox.SelectedItem;
this.NavigationService.Navigate(new CustomerDetailsPage(selectedCustomer));
Paul Stovell I think that using your suggestion will make your pages not garbage collected
because the whole instance will remain on Journal.