Windows Phone Navigation - Passing back to the page before - silverlight

I would like to click on a button to take me to a page
, then click on a listbox item, click on a button on the new page and pass it back to the page before without creating a new URI of the first page.
**First Page**
private void btnAddExistingMember_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/ChooseMember.xaml", UriKind.Relative));
}
**Second page after choosing listbox value**
private void btnAddSelected_Click(object sender, RoutedEventArgs e)
{
Member currMember = (Member)lstMembers.SelectedItem;
string memberID = currMember.ID.ToString();
//navigate back to first page here passing memberID
}
can it be done?
Thank you

You can store the member in the App.xaml.cs file. This is common file accesssible for all files in the application.
This works like a global variable.
//App.xaml.cs
int datafield ;
//Page1xaml.cs
(App.Current as App).dataField =10;
//Page2.xaml.cs
int x = (App.Current as App).dataField

You could create a manager class that would hold the member id. This manager class could then be accessed from both your first page and ChooseMember page.
An example of a Singleton Manager class :-
public class MyManager
{
private static MyManager _instance;
public static MyManager Instance
{
get
{
if (_instance == null)
{
_instance = new MyManager();
}
return _instance;
}
}
}

I found a solution at codeproject which was quite useful to me.
While moving from the second form, save your data in PhoneApplicationService.Current.State
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
// Called when a page becomes the active page in a frame
base.OnNavigatedFrom(e);
// Text is param, you can define anything instead of Text
// but remember you need to further use same param.
PhoneApplicationService.Current.State["Text"] = txtboxvalue.Text;
}
Go back using same NavigationService.GoBack(); and in OnNavigatedTo method, fetch the following code.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (PhoneApplicationService.Current.State.ContainsKey("Text"))
txtvalue.Text = (string)PhoneApplicationService.Current.State["Text"];
}
References:
MSDN: PhoneApplicationService Class
Original Solution at: How to pass values between pages in windows phone

Sounds to me like you want to set some object as the context for another page. Messaging in MVVM Light sounds like a good solution for this. Doesn't look like you're using MVVM so this may not be immediately applicable. This post pretty much lays out what I'm saying here.
Second Page
Create your SelectedObject property and make sure to call
RaisePropertyChanged(SelectedObjectPropertyName, oldValue, value, true);
The last parameter true says to broadcast this change in value to anyone listening. You'll need to wire up some other commands for listbox selected item and button click etc, but I won't go into that here since it's not directly related to your question. Selecting the Listbox item will simply set the data item for the first page like you want to accomplish. The button click can deal with the navigation.
First Page
In your view model constructor, register to receive the change broadcasted from Second Page
Messenger.Default.Register<PropertyChangedMessage<MyObject>>(this, (action) => UpdateObject(action.NewValue));
then define UpdateObject
private void UpdateObject(MyObject newObject)
{
LocalObjectProperty = newObject;
}

You can simply use
//first page
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
string value = string.Empty;
IDictionary<string, string> queryString = this.NavigationContext.QueryString;
if (queryString.ContainsKey("memberID"))
{
memberID = queryString["memberID"];
if (memberID != "-1")
//your code here
}
base.OnNavigatedTo(e);
}
//second page
private void btnAddSelected_Click(object sender, RoutedEventArgs e)
{
Member currMember = (Member)lstMembers.SelectedItem;
string memberID = currMember.ID.ToString();
string target = "/FirstPage.xaml";
target += string.Format("?memberID={0}", memberID);
NavigationService.Navigate(new Uri(target, UriKind.Relative));
}

Related

Balloon Notification Error when using the TaskbarIcon Library for a WPF Project

I'm trying to implement the a Balloon Notification to appear when a button is clicked however I keep receiving a specific error:
An object reference is required for the non-static field, method, or property
'TaskbarIcon.ShowBalloonTip(string, string, BalloonIcon)
I'm using the library Hardcodet.Wpf.TaskbarNotification;
The Method is
class NotifyIcon
{
public static void ShowStandardBalloon()
{
string title = "WPF NotifyIcon";
string text = "This is a standard balloon";
TaskbarIcon.ShowBalloonTip(title, text, BalloonIcon.Error);
}
}
and is called:
private void Button_Click(object sender, RoutedEventArgs e)
{
NotifyIcon ST = new NotifyIcon();
ST.ShowStandardBalloon();
}
Error is appearing under TaskbarIcon.ShowBalloonTip.
I've tried changing to public static void in the Notify Icon class however that didn't resolve anything.
You need to call the ShowBalloonTip on and instance of TaskbarIcon
TaskbarIcon TBIcon = new TaskbarIcon()
string title = "WPF NotifyIcon";
string text = "This is a standard balloon";
TBIcon.ShowBalloonTip(title, text, BalloonIcon.Error);

Windows Form Dropdown how to get previously selected value

I come from web background, now developing a windows application.
Application has drop down which shows the selected item (which comes from DB). I've a requirement that on selection of any other value than existing one perform xyz business logic.
I could use the index change event handler however, if they select other items and select back same I don't want to perform xyz business logic.
Therefore, can someone please help how it's possible to compare the selected value with one selected on load?
I could have session to store the previous state but not sure how can we do same in windows form.
In this case, your concept of session storage is a local storage variable. An example class:
public class MyForm : Form
{
private Int32 _selIdx = -1; //this is local to the Form and accessible anywhere within the MyForm class
public MyForm() { }
private void MyForm_Load(Object sender, EventArgs e)
{
//load database data, add to combo box, then capture the index
_selIdx = myComboBox.SelectedIndex;
}
//I prefer this method because it reacts to user interaction, and not programmatic change of index value
private void myComboBox_SelectionChangeCommitted(Object sender, EventArgs e)
{
//index changed, react
if (!_selIdx.Equals(myComboBox.SelectedIndex))
{
//not a match, do something...
}
}
}

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.

datagridview rowsremoved event gets called every time data loads

The datagridview rowsremoved event gets called every time the data gets loaded. It also makes sense to a certain extent that every time the data loads, the existing rows are removed. so technically the event should get called.
But how do i differenciate that from the actual delete button getting pressed. I don't think the key events should be used, that wouldn't be a clean approach.
Any help will be most appreciated.
You could use the UserDeletedRow event instead.
This is how we check to make sure the data has rows first:
If dataGridView.SelectedRows.Count > 0 Then
End If
See also: http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.userdeletingrow.aspx
You could have a private boolean variable to know when you are loading and when you are not.
private bool IsLoading { get; set; }
In the form Load event, you set the variable
private void MyForm_Load(object sender, EventArgs e)
{
this.IsLoading = true;
// do stuff
this.IsLoading = false;
}
private void DataGridView_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e)
{
if (this.IsLoading)
{
return;
}
//do stuff
}
Can you remove the event handler before loading the grid, and then re-add it afterward?

How to get activation events in composite children in Composite Application Guidance (PRISM)

I'm using the CAG and I've got some issues using the TabControl region. I worked out that by marking the view (and NOT the PresentationModel) as IActiveAware I can get an event when the view is activated/deactivated. That works well when the composite is simple and the TabItem is the view.
However, in my case I've got a composite inside the TabItem. It can listen to activation events but I'd like to propagate these events to its children so that they can react to them. Is there a way of doing that? I had a look at the RegionContext but it doesn't seem to work in my case (or maybe I'm doing it wrong).
Could it be that I'm missing out on something and an attached dependency or something else would solve my issue?
I decided to use the RegionContext to propagate the IsActive state within the region.
Set it up as:
Regions:RegionManager.RegionContext="{Binding Path=IsActive, Mode=TwoWay}"
on my tab view (which is IActiveAware). Then in the child view I can listen to changes:
RegionContext.GetObservableContext((DependencyObject)View).PropertyChanged += new PropertyChangedEventHandler(VehiclesPresentationModel_PropertyChanged);
private void VehiclesPresentationModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Value")
{
IsActive = (bool)RegionContext.GetObservableContext((DependencyObject)View).Value;
}
}
The remaining issue was that the reverse would work. Setting IsActive on the tab view doesn't active the tab :(
I added a custom behavior and now it works. The custom bahavior is like:
public class RegionReverseActiveAwareBehavior : RegionBehavior
{
public const string BehaviorKey = "RegionReverseActiveAwareBehavior";
protected override void OnAttach()
{
Region.Views.CollectionChanged += new NotifyCollectionChangedEventHandler(Views_CollectionChanged);
}
private void Views_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (var item in e.NewItems)
{
IActiveAware activeAwareItem = item as IActiveAware;
if (activeAwareItem != null)
{
activeAwareItem.IsActiveChanged += new EventHandler(activeAwareItem_IsActiveChanged);
}
}
}
if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var item in e.OldItems)
{
IActiveAware activeAwareItem = item as IActiveAware;
if (activeAwareItem != null)
{
activeAwareItem.IsActiveChanged -= new EventHandler(activeAwareItem_IsActiveChanged);
}
}
}
}
private void activeAwareItem_IsActiveChanged(object sender, EventArgs e)
{
IActiveAware activeAware = sender as IActiveAware;
if (activeAware != null &&
activeAware.IsActive)
{
Region.Activate(activeAware);
}
}
}
And then I set it up on the TabControl with:
RegionManager.GetObservableRegion(tabRegion).PropertyChanged +=
(sender, args) =>
{
if (args.PropertyName == "Value")
{
IRegion region = RegionManager.GetObservableRegion(tabRegion).Value;
region.Behaviors.Add(RegionReverseActiveAwareBehavior.BehaviorKey, new RegionReverseActiveAwareBehavior());
}
};
Hope that solves someone else's issue. Or maybe there's an easier way that I'm missing.
Have you looked at Prism EventAggregator? This can be implemented as some sort of MessageBus or Mediator...
You can Puplish events and everyone who needs be interested can subscribe to it...
If you look in the prism samples you find an implementation or something in the docs...
The Prism EventAggregator (EA) object allows you to publish events and subscribe to them through the EA object. This can be used with a single publisher and 0, 1 or many subscribers. I generally use the EA when I need to communicate between different parts of an application that are not tied together. For example, a menu item in the shell of a Prism application may need to invoke another view in a different module. The EA allows you to do this via pub/sub. However if a screen needs to make something happen on its own self, this ifs often better suited for the Command object.

Resources