Start and Back Button pressed in rapid succession WP7 - silverlight

I asked this question in a similar post but there have been significant updates since then, but still no results so I will try to re-ask the question with the updated information.
Basically I have a pivot view with 4 pivot items. If I create the scenario where I hit the windows key then rapidly press the back key my application will reopen without reconstructing (this is the expected outcome). The functionality of the application is there. I can press application bar buttons etc.
What doesn't work is the pivot items are frozen. If I was on Pivot item A and I press the start and back button quickly I come back to Pivot Item A. If I try to switch Pivot Items, the screen does not update, its "frozen" on Pivot Item A BUT the functionality of Pivot Item B is there. (I know this because the application bar Icons for Pivot Item B are now showing).
I have read many articles on proper tombstoning scenarios and how to approach this problem. My data IS being tombstoned correctly, and upon reactivation the tombstoned data works. No objects are null so I don't have any exceptions being thrown at me.
I check to see if I need to reload the Main ViewModel (I don't need to in this case so the UI elements being created initially are not being re created).
What does fix the problem however is if the application is reconstructed. Lets say I go to the marketplace from my app, let it finish loading and press back, My application will be refreshed and working fine since it properly deactivated and reconstructed istelf. I don't rely on constructors doing all the work so I am not missing any key elements not being set when they aren't fired in the windows/back button scenario.
Does anyone have any idea why my screen would not be updating?
constructor/loaded event/on navigated to event
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
if (App.firstTimeLoading == true)
{
App.firstTimeLoading = false;
}
BuildApplicationBar();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.DataContext = App.ViewModel;
App.viewIdentifier = StringResource.MainPageView;
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
String bookTitle;
App.Parser.appBookInfoDict.TryGetValue(CPlayerInventoryKeys.kInventoryKeyTitleShortTitle, out bookTitle);
PivotBackground.Title = bookTitle.ToUpper();
CreatePivotItems();
}
if (App.playerController.chapterPlayer.Source == null)
App.restoreStateClass.RestoreState();
//applies the proper background image
if (App.isDarkTheme)
{
BitmapImage bitmapImage = new BitmapImage(new Uri(StringResource.PanoramaBlackImage, UriKind.Relative));
BackgroundImage.ImageSource = bitmapImage;
BackgroundImage.Opacity = .85;
}
else
{
BitmapImage bitmapImage = new BitmapImage(new Uri(StringResource.PanoramaWhiteImage, UriKind.Relative));
BackgroundImage.ImageSource = bitmapImage;
BackgroundImage.Opacity = .5;
}
if (App.firstTimeLoading == false && PivotBackground.SelectedItem != SuggestedPivotItem)
BuildApplicationBar();
else if (PivotBackground.SelectedItem == SuggestedPivotItem)
{
BuildMarketPlaceApplicationBar();
}
base.OnNavigatedTo(e);
}

I found the answer. Since I had a media element open (play/paused) and I was implementing the "non tombstoned" method of hitting windows key and back button very quickly, the media element source was corrupt. Even though I reset this source, apparently it can be ignored and not function properly. All I had to do was add a line of code to the Application Deactivated handler.
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
App.MainAudioPlayer.Source = null; //(only showing line added)
}

The behavior you are describing seems to be solely related to the way you are manipulating data internally and constructing your layout. I tested this both in the emulator and on a couple of physical devices, both producing normal output (even when bound to a view model).
Try creating a new Pivot-based application (without all your data - just using the default template) and see if the problem persists. Also worth mentioning - are you testing on a device or in the emulator?

Are you using transitions from the toolkit?
Are they defined in XAML?
If so that could be the issue. There's a bug which is fixed in the next version.
The solution for now is to remove the transitions or define them in code.

Related

Can I get the NLogViewer to display entire log file?

I have a "long-running" WPF desktop application which uses NLog and the NLogViewer to display runtime status. It is used to monitor a database, pick up requests for processing, and then logging the results. (Yeah -- should have been a service, but we wanted to start out this way first -- baby steps.) The results are logged to a text log file and the NLogViewer shows the current items in the log in real time.
After the app has been running several hours, I've noticed I can only view a portion of the log -- from current entry back to an hour or so earlier. The scrollbar lets me scroll down to the most current entry, but stops way before the first entry. At this time, there isn't a lot of logging going on, i.e., no debugging or tracing, just Info, Warnings, and Errors, so I don't think the size of the log would have an impact.
Is there a way to have the NLogViewer let me view the entire log file or will it only show me a limited window into the log? Is there an alternate NLog viewer WPF control? I'm not really looking at a standalong NLog viewer at this time. If you need more information, please let me know.
Thanks!
Edit: I had some time to revisit this issue and got the NLogViewer source from GitHub. In the code-behind for the view, there is a hard coded value of 50 for the number of entries held in the items source for the ListView. For each item over 50, an item is removed from the beginning of the log. I could, of course, download the source and modify it to my liking which might be the final solution as the project hasn't been updated in 3 years. However, I might try and see if I can create a wrapper around the original control and allow for some basic extensions such as a configurable number of log entries to display and to always show the last entry added. If I have any success, I'll post what I did.
I made a new version of the NLogViewer. Without any limitation. You can also change the style if you want to
https://www.nuget.org/packages/Sentinel.NLogViewer
https://github.com/dojo90/NLogViewer
I spend a lot of time yesterday working on this, trying to just extend the existing class with new behaviors or properties. The biggest issue was with the hard coded 50 entries in a protected method that I couldn't access or override. And since the NLogViewer control is defined with XAML, I couldn't easily subclass it with a "non-XAML" class (compile errors). In the end, it seemed simpler to just use the original source code and make some mods to get the desired results.
I made the following changes:
I added 2 properties to the NLogViewer "view":
[Description("Automatically scroll last entry into view?"), Category("Data")]
public bool ScrollIntoView { get; set; } = true;
[Description("How many log entries should be kept in memory."), Category("Data")]
public int VisibleEntryCount { get; set; } = 50; // Original code default
These will control if the last log entry is scrolled into view and how many log entries will be available for display.
I modified the existing LogReceived handler to use the VisibleEntryCount property.
protected void LogReceived(NLog.Common.AsyncLogEventInfo log)
{
LogEventViewModel vm = new LogEventViewModel(log.LogEvent);
if (this.VisibleEntryCount == 0)
{
this.VisibleEntryCount = 50; // Original code default.
}
this.Dispatcher.BeginInvoke(new Action(() =>
{
if (this.LogEntries.Count >= this.VisibleEntryCount)
{
// We've reached our limit.
this.LogEntries.RemoveAt(0);
}
this.LogEntries.Add(vm);
}));
}
And I added a new event handler for whenever a new log entry is added. This will let me ensure the last entry is always visible (if specified by the user).
private void LogEntries_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (this.ScrollIntoView)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
if (this.logView != null)
{
int count = this.LogEntries.Count;
object selectedItem = (count > 0) ? this.LogEntries[count - 1] : null;
if (selectedItem != null)
{
this.logView.Dispatcher.BeginInvoke((Action)(() =>
{
this.logView.UpdateLayout();
this.logView.ScrollIntoView(selectedItem);
}));
}
}
}
}
}
It seems to be working OK. As always, I'm open to additional solutions or suggestions. Thanks!

WPF PRISM - Display multiple pop-up view on the same time

My Shell Window contains a secondary pop-up region from the Stock Trader RI demo application
infBehaviors:RegionPopupBehaviors.CreatePopupRegionWithName="{x:Static inf:RegionNames.SecondaryRegion}"
I am activating my views using the regionManager's RequestNavigate method:
regionManager.RequestNavigate(RegionNames.SecondaryRegion, new Uri(FooView, UriKind.Relative));
Everything works fine if I work just with a single View. However in my case I want to have multiple Pop-up Windows at once - like having multiple pop-up regions at once. It seems that the problem lies in the activation/deactivation of the views inside the region.
How to "persuade" not to deactivate my previous view inside the region?
Any idea?
I came across this issue and I thought I would expand on #Sebastjan's post since it might help someone down the road.
Using the code from the Stock Trader RI demo, in the RegionPopupBehaviors class, the RegisterNewPopupRegion method should look like this:
public static void RegisterNewPopupRegion(DependencyObject owner, string regionName)
{
IRegionManager regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
if (regionManager != null)
{
IRegion region = new AllActiveRegion(); //This was changed from SingleActiveRegion
DialogActivationBehavior behavior;
behavior = new WindowDialogActivationBehavior();
behavior.HostControl = owner;
region.Behaviors.Add(DialogActivationBehavior.BehaviorKey, behavior);
regionManager.Regions.Add(regionName, region);
}
}
For anyone that doesn't have the code sample for the stock trader app, you can find it here
It turned out that the solution is easier than I expected. Here is the solution in case if enybody needs it.
I just had to modify the RegionPopupBehaviours to use AllActiveregion instead of the original SingleActiveRegion and in the DialogActivation I had to remove the first call to the CloseContentDialog.
Hope that is helps.

Upgrade From WinForms to Telerik

I am trying to upgrade WinForms to Telerik Controls and when I am upgrading this
this.treeAccounting.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.TreeAccountingAfterSelect);
To this new RadControl Statement:
this.treeAccounting.SelectedNode += new Telerik.WinControls.UI.RadTreeViewEventArgs(this.TreeAccountingAfterSelect);
I get an error about best overloaded method match having invalid arguments for the TreeAccountingAfterSelect. Also it says cannot convert from 'method group' to 'Telerik.WinControls.UI.RadTreeNode'. Here is the function event for TreeAccountingAfterSelect.
private void TreeAccountingAfterSelect(object sender, Telerik.WinControls.UI.RadTreeViewEventArgs e)
{
string strSelectedNode = treeAccounting.SelectedNode.Text;
// Since the user can select any node (root, branch, leaf) of a tree in any order -
// cannot presume that they will select a root, then a leaf - so handle accordingly.
if (treeRootNames[(int)TreeNodes.TrialBalance] == strSelectedNode)
{
// Configure the Generator for doing a Trial Balance (detail) report
CrntReport = ReportTypes.TrialBalance;
CrntLocation = Locations.UNKNOWN;
// Based on default settings in the Report Property dialog (from App.Config) initialize
// screen controls.
lblCurrency.Visible = rptProperties.TBShowCurrencyCodes;
cboxCurrencyCode.Visible = rptProperties.TBShowCurrencyCodes;
this.Refresh();
// Setup the selections for the various parameters in the TrialBalance
// Parameters group.
SetupTBControls();
}
return;
}
I'm new to Telerik and I have tried different events and tried changing the parameter passed through the function and for some reason it isn't letting me use it like the WinForms. Can someone tell me where I am not understanding the change in WinForms to Telerik.
Looking at their documentation it seems that there is no SelectedNode event for a RadTreeView.
Instead you have
SelectedNodeChanged Occurs when selected node has been changed.
SelectedNodeChanging Occurs when the selected node is changing
And you don't use the RadTreeViewEventArgs to bind the event handler but a RadTreeViewEventHandler
So perhaps you need to write
this.treeAccounting.SelectedNodeChanged +=
new RadTreeViewEventHandler(this.TreeAccountingAfterSelect);
The syntax for delegate will allow also
this.treeAccounting.SelectedNodeChanged += this.TreeAccountingAfterSelect;

Do XAML objects remain virtually present when leaving a XAML page in Windows 8 App?

I use the MVVM Light Toolkit to define the association between the view-model and the view.
The container is instructed to register a view-model as a singleton instance. Thus, the same instance will always be returned when the GagaViewModel is required:
public GagaViewModel GagaViewModel
{
get
{
var vm = ServiceLocator.Current.GetInstance<GagaViewModel>();
vm.Setup(); //Clear the ObservableCollection
return vm;
}
}
You can click on a thumbnail item on PriorGaga.xml. The self-chosen item is then selected in the GridView "MyGridView" in Gaga.xaml. Code-behind file of Gaga.xaml:
protected override async void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
var itemId = navigationParameter as String;
if (String.IsNullOrEmpty(itemId))
{
throw new ArgumentException("navigationParameter was either null or empty");
}
await ((GagaViewModel)DataContext).Init(itemId); //Busy(-Indicator) while loading data from server, filling the ObservableCollection and writing the selected item down
BringItemIntoView();
}
private void BringItemIntoView()
{
var vm = (GagaViewModel)DataContext;
Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() => MyGridView.ScrollIntoView(vm.SelectedItem));
}
That works fine. As a sample: Item #45 appears within the viewport immediately (correct viewport position from the beginning).
But when you click the back button and return to Gaga.xaml by selecting an arbitrarily thumbnail item (let's just say #29), you will see item #1 and then the switch to #29 (the viewport is moving over the container). Do someone know what's going on under there? Are there any virtualized items in the container from the preceding Gaga.xaml visit?
My understanding is that the lifespan of the instance of your Gaga page is determined by its NavigationCacheMode property. By default, it is set to Disabled. Assuming that you haven't changed this property, you should be seeing a new instance of your Gaga page every time you navigate to it. You can verify this behavior by setting a breakpoint in its constructor. Consequently, I would think that each time you navigate to Gaga, the behavior of the UI should be identical, because everything is fresh.
(I wanted to add this as a comment, since I haven't actually answered your question, but sadly I do not have enough rep. I apologize in advance; please do not smite me down!)

Detect when a row is edited in a DataGrid

I've been trying to google this but have been unable to find a solution that works for me.
I have a DataGrid that is displaying some info from a SQL table that the client dosn't know about.
The client just sends a request to the server and gets a List<SomeClass> as a response that it then displays in a DataGrid.
I need to detect when the user makes change to a row and I need the new values that the user entered.
Currently I'm using RowEditEnding event. And the method that handles this event can then:
private void editRowEventHandler(object sender, DataGridRowEditEndingEventArgs e)
{
SomeClass sClass = e.Row.DataContext as SomeClass;
// Send sClass to the server to be saved in the database...
}
This gives me the row that was being edited. But it gives me the row before the changes, and I'm unable to figure out how to get the row after the changes happen.
Is there anyone here that knows how I can do this or can point me in a direction where I might be able to find out?
See the discussion here, to avoid reading out cell-by-cell.
private void OnRowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if (e.EditAction == DataGridEditAction.Commit) {
ListCollectionView view = CollectionViewSource.GetDefaultView(dataGrid.ItemsSource) as ListCollectionView;
if (view.IsAddingNew || view.IsEditingItem) {
this.Dispatcher.BeginInvoke(new DispatcherOperationCallback(param =>
{
// This callback will be called after the CollectionView
// has pushed the changes back to the DataGrid.ItemSource.
// Write code here to save the data to the database.
return null;
}), DispatcherPriority.Background, new object[] { null });
}
}
}
In your case, you are trying to detect the change in object. It comes down to the properties of the SomeClass, thus you need to focus on "Cell" instead of "Row"
Assuming your datagrid is resultGrid, i come up with the below code:
resultGrid.CellEditEnding += resultGrid_CellEditEnding;
void resultGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
var yourClassInstance = e.EditingElement.DataContext;
var editingTextBox = e.EditingElement as TextBox;
var newValue = editingTextBox.Text;
}
the "e" also contains information about Row and Column of the Cell. Thus you will know which editor the cell is using. In this case, i assume that it is a textbox.
Hope it help.

Resources