I need help passing data from one WPF form to another. I have a main window with two other windows that will prompt the user for information. I want to end up with all the information in the first form so that I can store the data later on. The second form must return the Reservation and Room information when you click the OK button on the second form. The third form must return the Person information when you click OK.
public partial class MainWindow : Window
{
private string message;
public MainWindow()
{
InitializeComponent();
}
protected void Exit_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
}
protected void Create_Reservation_Click(object sender, RoutedEventArgs e)
{
Reservation PersonReservation = new Reservation();//Create a reservation instance
Room PersonRoom = new Room(); //Create an instance of a room
Person myPerson = new Person();//Create an instance of a person
CreateResRoom createReservationRoom = new CreateResRoom();//Create a instance of the CreateReservation WPF Form
createReservationRoom.Show();
Here it is supposed to set the room, reservation and person instance that I created equil to their corresponding instances in the CreateResRoom class.
I think the problem lies here, because it keeps continuing before it opens the CreateResRoom form.
PersonRoom = createReservationRoom.myRoom;
PersonReservation = createReservationRoom.myReservation;
}
}
That was my first class, the second and third will follow.
public partial class CreateResRoom : Window
{
Person myPerson;
public CreateResRoom()
{
InitializeComponent();
myReservation = new Reservation();
myRoom = new Room();
myPerson = new Person();
}
public Room myRoom
{
get;
set;
}
public Reservation myReservation
{
get;
set;
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
private void btnOk_Click(object sender, RoutedEventArgs e)
{
myRoom.RoomBeds = txtHeadCount.Text;
myRoom.RoomNumber = 1;
myRoom.RoomPrice = 20;
myRoom.RoomType = cboRoomType.Text;
myReservation.ResEndDate = dpEnd.ToString();
myReservation.ResStartDate = dpStart.ToString();
CreateRes createReservation = new CreateRes();
createReservation.Show();
//I think the same problem lies here that is in the MainWindow.
myPerson = createReservation.myPerson;
this.Close();
}
}
And the last class follows:
public partial class CreateRes : Window
{
public Person myPerson
{
get;
set;
}
public CreateRes()
{
InitializeComponent();
myPerson = new Person();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
}
private void btnOk_Click(object sender, RoutedEventArgs e)
{
myPerson.FirstName = txtFName.Text;
myPerson.LastName = txtLName.Text;
myPerson.IdNumber = Convert.ToInt32(txtIdNumber.Text);
myPerson.PhoneNumber = Convert.ToInt32(txtPhoneNumber.Text);
myPerson.AddressCity = txtAddressCity.Text;
myPerson.AddressStreet = txtAddressStreet.Text;
myPerson.AddressProvince = txtAddressProvince.Text;
myPerson.AddressPostalCode = txtAddressPostalCode.Text;
this.Close();
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
Just make a overload constructor which takes parameters of the window in which you want to retrieve.
Example:
Suppose we want a user to login from our MainWindow( i.e Login Window ) and we want to pass an int ID / string Email to our second form to retrieve data of logging user.
Than We have to first overload our second wpf form constructor. You can either make default constructor to do this or make an overload constructor for this work.
SecondForm:
public secondForm()
{
//Your Default Constructor Logic
}
public secondForm(string email_ )
{
//Your Overload Constructor Logic
}
Now in MainWindow from where we are logging and passing our EMail
MainWindow:
public void btnLogin()
{
//On Success
SecondWindow sw = new SecondWindow(txtBoxEMail.Content);
sw.Show();
}
A pattern you can use for this sort of thing is to have each form be responsible for creating the instance on ok click and then provide the object via a property get.
public partial class SomeForm: Window
{
public SomeClass MyProperty { get; private set; }
private void btnOk_Click(object sender, RoutedEventArgs e)
{
this.MyProperty = new SomeClass();
//additional setter logic here
this.Close();
}
}
Then you would access it from a parent form like this (notice the use of ShowDialog() http://msdn.microsoft.com/en-us/library/system.windows.window.showdialog(v=vs.110).aspx for easy checking of whether ok was clicked or not).
protected void Create_Reservation_Click(object sender, RoutedEventArgs e)
{
SomeClass myObj;
SomeOtherClass myOtherObj;
SomeForm myForm = new SomeForm();
if(myForm.Show().Value)
{
myObj = myForm.MyProperty;
}
SomeOtherForm myOtherForm = new SomeOtherForm();
if(myOtherForm.ShowDialog().Value)
{
myOtherObj = myOtherForm.MyOtherProp;
}
//save myObj & myOtherObj or whatever you need to do with them
Use the "normal way", here is a short overview.
First create a Data Context:
public class DC_Reservation() : INotifyPropertyChanged {
protected Reservation _PersonReservation ;
public Reservation PersonReservation {
get { return _PersonReservation ; }
set {
_PersonReservation = value;
NotifyPropertyChanged("PersonReservation ");
}
}
protected Room _PersonRoom ;
public Room PersonRoom {
get { return _PersonRoom ; }
set {
_PersonRoom = value;
NotifyPropertyChanged("PersonRoom");
}
}
protected Person _myPerson ;
public Person myPerson {
get { return _myPerson ; }
set {
_myPerson = value;
NotifyPropertyChanged("myPerson ");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged( string PropertyName ) {
if ( PropertyChanged != null ) {
PropertyChanged( this, new PropertyChangedEventArgs( PropertyName ) );
}
}
}
In the MainWindows you can assign and use the dataContext :
public partial class MainWindow : Window {
DC_Reservation dataContext {
get { return DataContext as DC_Reservation; }
}
private string message;
public MainWindow() {
InitializeComponent();
DataContext = new DC_Reservation();
}
protected void Create_Reservation_Click(object sender, RoutedEventArgs e) {
dataContext.PersonReservation = new Reservation();//Create a reservation instance
dataContext.PersonRoom = new Room(); //Create an instance of a room
dataContext.myPerson = new Person();//Create an instance of a person
CreateResRoom createReservationRoom = new CreateResRoom();//Create a instance of the CreateReservation WPF Form
// I'm not sure whether the next line is required.
createReservationRoom.DataContext = DataContext;
createReservationRoom.Show();
}
}
You can assign the DataContext in the constructor, but I think the better way is to define the DataContext in the MainWindow, in the other windows you can use the DesignContext:
<Window.DataContext>
<local:DC_Reservation />
</Window.DataContext>
So you can use the same DataContext over all forms ...
With DataBindings you can bind the input to the field:
<TextBox Text="{Binding FirstName, Path=myPerson, Mode=TwoWay}" />
I found another answer that Zarathos posted Jan 16 '13 at 21:43
for a different question
Use a public static class and access it from anywhere.
public static class Globals
{
public static String s_Name = "Mike"; //Modifiable in Code
public const int32 VALUE = 10; // unmodifiable
}
Then you can use it anywhere, provided you are working on the same namespace
string name = Globals.s_Name;
Related
I am tying to further understand MVVM with some example scenario. I have a rootpage with a 'maindisplay' textblock. I would like to display 'status' or 'scenarios' from activation of any form of UI eg. togglebutton on the 'maindisplay' textblock.
I am able to bind the the page navigation info in the rootpageviewmodel to the textblock. However, I am not able to achieve the result when displaying info from different page.
I have checked another post multiple-viewmodels-in-same-view & Accessing a property in one ViewModel from another it's quite similar but it didn't work.
Please help. Thanks.
While accessing the RootPageViewModel should retain the instance?
View
<TextBlock Text="{x:Bind RootViewModel.MainStatusContent, Mode=OneWay}"/>
RootPage.xaml.cs
public sealed partial class RootPage : Page
{
private static RootPage instance;
public RootPageViewModel RootViewModel { get; set; }
public RootPage()
{
RootViewModel = new RootPageViewModel();
this.InitializeComponent();
// Always use the cached page
this.NavigationCacheMode = NavigationCacheMode.Required;
}
public static RootPage Instance
{
get
{
if (instance == null)
{
instance = new RootPage();
}
return instance;
}
}
private void nvTopLevelNav_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
{
if (args.IsSettingsInvoked)
{
contentFrame.Navigate(typeof(SettingsPage));
RootViewModel.MainStatusContent = "Settings_Page";
}
else
{
var navItemTag = args.InvokedItemContainer.Tag.ToString();
RootViewModel.MainStatusContent = navItemTag;
switch (navItemTag)
{
case "Home_Page":
contentFrame.Navigate(typeof(HomePage));
break;
case "Message_Page":
contentFrame.Navigate(typeof(MessagePage));
break;
}
}
}
}
RootPage ViewModel:
public class RootPageViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private static RootPageViewModel instance = new RootPageViewModel();
public static RootPageViewModel Instance
{
get
{
if (instance == null)
instance = new RootPageViewModel();
return instance;
}
}
public RootPageViewModel()
{
}
private string _mainStatusContent;
public string MainStatusContent
{
get
{
return _mainStatusContent;
}
set
{
_mainStatusContent = value;
OnPropertyChanged();
}
}
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
MessagePage.xaml.cs - to access RootPage ViewModel
public sealed partial class MessagePage : Page
{
public MessagePageViewModel MessageViewModel { get; set; }
public MessagePage()
{
MessageViewModel = new MessagePageViewModel();
this.InitializeComponent();
// Always use the cached page
this.NavigationCacheMode = NavigationCacheMode.Required;
}
private void Message1_Checked(object sender, RoutedEventArgs e)
{
RootPageViewModel.Instance.MainStatusContent = "Message 1 Selected";
}
private void Message1_Unchecked(object sender, RoutedEventArgs e)
{
RootPageViewModel.Instance.MainStatusContent = "Message 1 De-Selected";
}
}
When I debug the value did write to the instance but did't update the TextBlock. Did I do anything wrong in my XAML binding?
UWP C# MVVM How To Access ViewModel from Other Page
The better way is make static variable for RootPage, but not make singleton instance for RootPage and RootPageViewModel.
For example:
public RootPage ()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
Instance = this;
RootViewModel = new RootPageViewModel();
}
public static RootPage Instance;
Usage
private void Message1_Checked(object sender, RoutedEventArgs e)
{
RootPage.Instance.RootViewModel.MainStatusContent = "Message 1 Selected";
}
private void Message1_Unchecked(object sender, RoutedEventArgs e)
{
RootPage.Instance.RootViewModel.MainStatusContent = "Message 1 De-Selected";
}
Is there a way to reload a form variables?
string a = ""
public form1()
{
InitializeComponent();
}
private void form1_load(object sender, EventArgs e)
{
a = "Something";
textbox1.Text = a;
}
Is there a way to reset the value of "a" to empty and the text displayed on the textbox? I can create a function to set the value of "a" to empty and empty the textbox but as I have many variables, I want to avoid doing that as I might miss one that will cause a bug. I was wondering if there is a way to do that.
I don't want to reinitialize the form as its kinda slow to reload the form graphics again. Thanks for any help.
I would work like this:
public struct Snapshot
{
public string a;
public int? b;
}
private Snapshot _initial;
private void form1_Load(object sender, EventArgs e)
{
_initial = this.CreateSnapshot();
}
private Snapshot CreateSnapshot()
{
return new Snapshot()
{
a = textbox1.Text,
b = int.TryParse(textbox2.Text, out int x) ? (int?)x : null
}
}
private void button1_Click(object sender, EventArgs e)
{
this.RestoreSnapshot(_initial);
}
private void RestoreSnapshot(Snapshot snapshot)
{
textbox1.Text = snapshot.a;
textbox2.Text = snapshot.b.HasValue ? snapshot.b.Value.ToString() : "";
}
Your _initial Snapshot happens at form1_Load to save where the form was at at the beginning. You then just call this.RestoreSnapshot(_initial); whenever you want to revert your values.
The advantage of this kind of approach is that it allows you to make multiple snapshots and implement an "undo" function and, because you have separated your form from your data, it makes testing easier.
Have you considered using a wrapper around your properties, with change notification? You can then use data binding to make the value and the text boxes update together. See the following:
public partial class Form1 : Form
{
public NotifyProperty<string> A { get; } = new NotifyProperty<string>();
public NotifyProperty<double> B { get; } = new NotifyProperty<double>();
public void Reset()
{
A.Value = "Something";
B.Value = 3.14d;
}
public Form1()
{
InitializeComponent();
textBox1.DataBindings.Add("Text", A, "Value", true, DataSourceUpdateMode.OnPropertyChanged);
textBox2.DataBindings.Add("Text", B, "Value", true, DataSourceUpdateMode.OnPropertyChanged);
Reset();
}
private void simpleButton1_Click(object sender, EventArgs e)
{
Reset();
}
}
public class NotifyProperty<T> : INotifyPropertyChanged
{
private T _value;
public T Value
{
get => _value;
set
{
if (_value != null && _value.Equals(value)) return;
_value = value;
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs("Value"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
When Reset() is called, both the values in A and B and textBox1 and textBox2 will be updated. Also, when you are obtaining the results from the form, you can use A and B (you don't need to use the textboxes, because when the user types text, A and B will be updated automatically).
First Form
public partial class FrmCasher : XtraForm
{
public static FrmCasher instanceC;
public SimpleLabelItem num;
public FrmCasher()
{
InitializeComponent();
num = lableTableID; // We want to change lableTableID's text value
instanceC = this;
}
}
Second Form
public partial class FrmHall : DevExpress.XtraEditors.XtraForm
{
private void FrmHall_FormClosing(object sender, FormClosingEventArgs e)
{
FrmCasher.instanceC.num.Text = "Our new String value...";
}
}
I am having this very strange problem where i am creating a list of some objects in one class then trying to access it in another class but it's coming empty in other class:
My first class where i am populating the list:
namespace dragdrop
{
struct BR
{
private string var;
public string Var
{
get { return var; }
set { var = value; }
}
private string equalsTo;
public string EqualsTo
{
get { return equalsTo; }
set { equalsTo = value; }
}
private string output;
public string Output
{
get { return output; }
set { output = value; }
}
private string els;
public string Els
{
get { return els; }
set { els = value; }
}
private string elsOutput;
public string ElsOutput
{
get { return elsOutput; }
set { elsOutput = value; }
}
}
public partial class Form1 : Form
{
//******************
private List<BR> list = new List<BR>(); //This is the list!
//******************
internal List<BR> List
{
get { return list; }
set { list = value; }
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string[] vars = new string[] { "Name", "Gender", "Age", "Address", "email" };
comboBox1.DataSource = vars;
}
private void button1_Click(object sender, EventArgs e)
{
BR b = new BR();
b.Var = comboBox1.SelectedItem.ToString();
b.EqualsTo = textBox1.Text;
b.Output = textBox2.Text;
list.Add(b);
//*****************
textBox1.Text = List.Count.ToString(); //This gives the correct count value!
//*****************
//this.Close();
}
}
}
I am accessing it in second class like:
namespace dragdrop
{
public partial class Ribbon1
{
private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
{
}
private void button1_Click(object sender, RibbonControlEventArgs e)
{
Form1 form = new Form1();
List<BR> l = form.List; ;
//*******************
MessageBox.Show(form.List.Count.ToString()); //This strangely gives count 0!
//*******************
}
}
}
I have even tried making everything public in first class but no matter what i do, im always getting empty list in second class.
The is no relation what-so-ever between Form1 and Ribbon1, how can one then access an instance of the other?
With this:
Form1 form = new Form1(); // new instance of Form1
List<BR> l = form.List; ; // of course the list is empty in a new instance!
you can never access values from another instance of Form1.
Since I have no idea how your classes are connected I cannot give you more advice than have a look at this good overview of OO-relationships. You have to connect them somehow for it to work, I would very much recommend composition // aggregation (same thing, different schools).
All i needed to do was make the list a static member in class one, that solved the issue of having different value when i tried to create a new instance of Form1 in Ribbon1 class.
private static List<BR> list = new List<BR>();
Well I know this question has been asked a couple of times but none of the solutions worked for me. I simply want to pass a value from one form to a textbox in a different form.
On the first form I have a data grid when double-clicked on it obtains a value from the datagrid column.
public partial class AvailableRooms : Form
{
private void DCRoom(object sender, DataGridViewCellMouseEventArgs e)
{
var roomnum = dgRooms.Rows[e.RowIndex].Cells["iRoomNum"].Value.ToString();
RoomBooking rb = new RoomBooking();//The second form
rb.roomnumber = roomnum;
rb.Show();
}
}
On the second form I have set the properties of the textbox
public partial class RoomBooking : Form
{
public RoomBooking()
{
StartPosition = FormStartPosition.CenterScreen;
InitializeComponent();
}
public string roomnumber
{
get { return txtRoomNum.Text; }
set {txtRoomNum.Text = value;}
}
}
Thanks in advance for the help?
You have to find the control to edit it as it does not belong to the class.
private void DCRoom(object sender, DataGridViewCellMouseEventArgs e)
{
//new value
var roomnum = dgRooms.Rows[e.RowIndex].Cells["iRoomNum"].Value.ToString();
//The second form
RoomBooking rb = new RoomBooking(this);
//The textbox
TextBox roomnumber = (TextBox)rb.Controls.Find("roomnumber", true)[0];
//set the value of the textbox
roomnumber.Text = roomnum;
//show second form
rb.Show();
}
I would define the RoomBookingclass like this:
public partial class RoomBooking : Form
{
public RoomBooking() // WinForms Designer requires a public parameterless constructor
{
InitializeComponent();
StartPosition = FormStartPosition.CenterScreen;
}
public RoomBooking(string roomNumber) : this() // Constructor chaining
{
RoomNumber = roomNumber;
txtRoomNum.Text = RoomNumber;
}
public string RoomNumber { get; set; }
}
Then:
public partial class AvailableRooms : Form
{
private void DCRoom(object sender, DataGridViewCellMouseEventArgs e)
{
var roomNumber = dgRooms.Rows[e.RowIndex].Cells["iRoomNum"].Value.ToString();
var roomBooking = new RoomBooking(roomNumber);
roomBooking.Show();
}
}
Hope this helps.
I'm studying design patterns right now, I'm fairly new to this model-view-presenter, although I have already experience in asp.net mvc I'm trying to do an implementation of mvp in winforms.
The string in the textbox will be sorted with an algorithm based on the combobox. Right now when I click the button it throws a null reference exception
Here is the UI:
Here are my classes and codes:
class FormPresenter
{
private ISortingView _view;
private string _algorithm;
private StringToSortModel sortMe = new StringToSortModel();
public FormPresenter(ISortingView view)
{
_view = view;
_view.sortTheString += view_sortString;
sortMe.sortThis = view.stringToSort;
_algorithm = _view.algorithm;
//Algorithm = view.stringToSort;
//sortingform.sortTheString += (obj
}
private void view_sortString(object sender, EventArgs e)
{
SortContext context = new SortContext();
_view.sortedText = context.Sort(sortMe.sortThis.ToCharArray());
}
}
interface ISortingView
{
event EventHandler sortTheString;
string stringToSort { get; }
string algorithm { get; }
string sortedText { get; set; }
}
public partial class SortingForm : Form, ISortingView
{
public SortingForm()
{
InitializeComponent();
comboBox1.Items.Add("Bubble Sort");
comboBox1.Items.Add("Insertion Sort");
comboBox1.SelectedItem = "Bubble Sort";
textBox1.Text = "Emiri";
}
public event EventHandler sortTheString;
public string algorithm { get { return comboBox1.SelectedItem.ToString(); } }
public string stringToSort { get { return textBox1.Text; } }
public string sortedText { get { return label2.Text; } set { label2.Text = value; } }
private void Form1_Load(object sender, EventArgs e)
{
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
//char[] x = textBox1.Text.ToCharArray();
//SortContext con = new SortContext();
//con.SetSortStrategy(new InsertionSort());
//label2.Text = con.Sort(x);
//if(sortString != null)
//{
//this prodcues a null exception error
sortTheString(sender, e);
//}
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var mainForm = new SortingForm();
var presenter = new FormPresenter(mainForm);
Application.Run(new SortingForm());
}
}
I have not included the codes for the model and the classes the contains the sorting functions to keep this post short. The problem I have is that when button is clicked it throws a null reference exception error, something that I have been stuck on for hours already.
Sir/Ma'am your answers would be of great help. Thank you++
Your null is coming from this line
sortTheString(sender, e);
because you are not using the same form instance in your Presenter. Change to this in your main...
Application.Run(mainForm);
The event handler does not have any subscribers (because of the Application.Run(new SortingForm()); C# will treat that as null rather than an empty subscriber list.
ISortingView mainForm = new SortingForm();
var presenter = new FormPresenter(mainForm);
Application.Run(mainForm as Form);