I have a issue with passing information from one wpf window to another. For some reason when main window is loaded nothing is set in the label, I need to be able to keep the data in a string to use for anything (label not important but shows what I mean)?
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public string MyData { get; set; }
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
label1.Content = MyData;
}
public partial class LoginWindow : Window
{
public LoginWindow()
{
InitializeComponent();
}
private void button2_Click(object sender, RoutedEventArgs e)
{
string mytext = "blabla";
MainWindow fromloginwindow = new MainWindow();
fromloginwindow.Mydata = mytext;
}
Or am I doing this the wrong way round?
EDIT:
Please do not go on a tangent about the label its unimportant I need to be able to get and set a string for use anywhere in the MainWindow. Also the string "mytext" is also irrelevant as obviously I will not be setting the string this way.
It sounds like you are running into an event lifecycle issue; the calls to the Loaded event happen pretty quickly and thus, the chance to set the text has passed. Instead, what you should do is either:
1) Bind the Property to the Label in the XAML
public event PropertyChangedEventHandler PropertyChanged;
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
protected string _myData = string.Empty;
public string MyData
{
get { return _myData; }
set { _myData = value; NotifyPropertyChanged("MyData"); }
}
protected void NotifyPropertyChanged(string propName)
{
var methods = PropertyChanged;
if(methods != null)
methods(this, new PropertyChangedEventArgs(propName));
}
<Label Content="{Binding MyData}" />
2) Set the control text via another method (or inside the property declaration):
public void SetLabel(string text)
{
label1.Content = text;
}
protected void button2_Click(object sender, RoutedEventArgs e)
{
MainWindow x = new MainWindow();
x.SetLabel("blabla");
}
The Loaded event occurs before you set MyData, change the code like this:
public partial class MainWindow : Window
{
public MainWindow(string data)
{
MyData = data
InitializeComponent();
}
Have you tried passing the value to the second window through the window's constructor?
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public MainWindow(string data)
: this()
{
label1.Content = data;
}
}
public partial class LoginWindow : Window
{
public LoginWindow()
{
InitializeComponent();
}
private void button2_Click(object sender, RoutedEventArgs e)
{
string mytext = "blabla";
MainWindow fromloginwindow = new MainWindow(mytext);
}
}
Related
My environment is:
Windows 11
Windows Form App created by the Windows Forms App template of Visual Studio 2022.
Problem:
I have a simple Windows Form with only a Textbox and a Button.
I am trying to update the Textbox text with new data whenever the button is pressed.
The binding works when the Windows Form is loaded. The text "12.34" appears in the Textbox.But when I click on the button, the Textbox is not updated with the new data.
Here is my code:
namespace WatchChart;
public partial class WatchForm:Form
{
public class BidAsk
{
public string? BidString { get; set; }
}
public WatchForm()
{
InitializeComponent();
}
private void MyForm_Load(object sender, EventArgs e)
{
var bid = new BidAsk() { BidString = "12.34" };
bidTextBox.DataBindings.Add(nameof(TextBox.Text), bid, nameof(BidAsk.BidString));
}
private void displayButton_Click(object sender, EventArgs e)
{
var bidask = new BidAsk();
bidask.BidString = "23.45";
}
}
Any help will be greatly appreciated,Charles
The first potential issue is that you need the bound variable to be a member of the main form (instead of making a local var inside the methods). The other potential issue is making sure to enable two-way binding. The BidString property should be implemented similar to the BidAsk shown in order to fire a PropertyChange event whenever its value changes.
class BidAsk : INotifyPropertyChanged
{
string _bidString = string.Empty;
public string BidString
{
get => _bidString;
set
{
if (!Equals(_bidString, value))
{
_bidString = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Test
Here's the code I used to test this answer::
public partial class MainForm : Form
{
public MainForm() => InitializeComponent();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
BidAsk = new BidAsk();
textBoxBid.DataBindings.Add(
propertyName: nameof(TextBox.Text),
dataSource: BidAsk,
dataMember: nameof(BidAsk.BidString));
buttonDisplay.Click += onClickButtonDisplay;
}
BidAsk BidAsk { get; set; }
private void onClickButtonDisplay(object? sender, EventArgs e)
{
// Test string gobbledegook
var marklar = Guid.NewGuid().ToString().Substring(0, 11);
BidAsk.BidString = marklar;
}
}
You are creating a new BidAsk (let's call it bidAsk1) on load, and binding to that. Then on the button click, you are creating another BidAsk (bidAsk2) and setting the content. Your textbox is still bound to bidAsk1, not bidAsk2 so it will not be updated.
Try keeping a reference to the bound object:
namespace WatchChart;
public partial class WatchForm:Form
{
public class BidAsk
{
public string? BidString { get; set; }
}
private BidAsk bid;
public WatchForm()
{
InitializeComponent();
}
private void MyForm_Load(object sender, EventArgs e)
{
bid = new BidAsk() { BidString = "12.34" };
bidTextBox.DataBindings.Add(nameof(TextBox.Text), bid, nameof(BidAsk.BidString));
}
private void displayButton_Click(object sender, EventArgs e)
{
bid.BidString = "23.45";
}
}
I developed an app, where the user sects on order from a list. If the order is selected, the EditOrderWindow shows. From this window, the user can add items to the Order by. This is done in a sub dialog AddItemWindow. Works fine for the first order.
However, if a second order is edited, the AddItemWindow shows again after its been closed. For the third order edited it shows three times aso.
I couldn't figure out why this happens, and how to prevent it.
ViewModel
public class ViewModel
{
public ICommand EditOrderCommand { get; set; }
public ICommand AddItemCommand { get; set; }
public event EventHandler<int> EditOrder;
public event EventHandler<int> AddItem;
public event EventHandler<int> ItemAdded;
public ViewModel()
{
//Is fired when an item in the datagrid in Control OrderList is doubleclicked
EditOrderCommand = new ICommand();
EditOrderCommand.Executed += EditOrderCommand_Executed();
//Is fired when the users click on add in EditOrderWindow
AddItemCommand = new ICommand();
AddItemCommand.Executed += AddItemCommand_Executed();
}
private void EditOrderCommand_Executed(object sender, EventArgs e)
{
if (SelectedOrder != null)
{
EditOrder(this, SelectedOrder.Id);
}
}
private void AddItemCommand_Executed(object sender, EventArgs e)
{
AddItem(this, new EventArgs());
}
}
Control: OrderList
public partial class OrderList : UserControl
{
ViewModel vm;
public OrderList()
{
InitializeComponent();
//DataContext is set in xmal
vm = (ViewModel)this.DataContext;
vm.EditOrder += Vm_EditOrder;
}
private void Vm_EditOrder(object sender, int e)
{
EditOrderWindow s = new EditOrderWindow(vm);
s.ShowDialog();
s = null;
}
Window: EditOrderWindow
public partial class EditOrderWindow : Window
{
ViewModel vm;
AddItemWindow aiw;
public EditOrderWindow(ViewModel _vm)
{
InitializeComponent();
vm = _vm;
this.DataContext = vm;
vm.AddItem -= Vm_AddItem;
vm.AddItem += Vm_AddItem;
}
private void Vm_AddItem(object sender, EventArgs e)
{
if (aiw == null)
{
aiw = new AddItemWindow(vm);
}
aiw.ShowDialog();
aiw = null;
}
}
Window: AddItemWindow
public partial class AddItemWindow : Window
{
public AddItemWindow(ViewModel _vm)
{
InitializeComponent();
this.DataContext = _vm;
_vm.ItemAdded -= _vm_ItemAdded;
_vm.ItemAdded += _vm_ItemAdded;
}
private void _vm_ItemAdded(object sender, EventArgs e)
{
this.Close();
}
}
I have a MainWindow and there is a button in MainWindow to open ClientWindow.
private void btnMakeClient_Click(object sender, RoutedEventArgs e)
{
ClientWindow window = new ClientWindow();
window.Show();
}
Forexample; if i 3 times click, then it opens 3 ClientWindow (chatWindow). How can i pass data(text) between these clone windows? I mean i write "hi how are you?" in a ClientWindow (chatWindow) and it appears in another windows too.
I thought that if i pass data(text) from ClientWindow with a MainWindow constructor and get it back with ClientWindow constructor would solve my problem but it did not. Here is my code
MainWindow:
public partial class MainWindow : Window
{
public string TextContent { get; set; }
public MainWindow()
{
InitializeComponent();
}
public MainWindow(string txtContext)
{
InitializeComponent();
TextContent = txtContext;
ClientWindow window = new ClientWindow(TextContent);
}
private void btnMakeClient_Click(object sender, RoutedEventArgs e)
{
ClientWindow window = new ClientWindow();
window.Show();
}
}
ClientWindow:
public partial class ClientWindow : Window
{
public string Chatcontent { get; set; }
public ClientWindow()
{
InitializeComponent();
}
public ClientWindow(string chatContent)
{
InitializeComponent();
Chatcontent = chatContent;
if (chatContent != string.Empty)
{
this.txtContent.Text += Environment.NewLine + Chatcontent;
txtChat.Clear();
}
}
private void btnSend_Click(object sender, RoutedEventArgs e)
{
MainWindow window = new MainWindow(txtChat.Text);
}
}
This is where MVVM shines. Create a ViewModel object that contain a String property and a Command to add text to this property and then in client windows just call this command with the text to add as parameter.
Note that I use DelegateCommand as described here but you can also use RelayCommand.
ViewModel
public class YourViewModel : INotifyPropertyChanged {
private String _textContent;
public String TextContent {
get {return _textContent;}
set {
_textContent = value;
OnPropertyChanged("TextContent");
}
}
private DelegateCommand _cmdAddTextToChat;
/// <summary>
/// Add text to TextContent
/// </summary>
public DelegateCommand CmdAddTextToChat {
get { return _cmdAddTextToChat ?? (_cmdAddTextToChat = new DelegateCommand(AddTextToChat)); }
}
private void AddTextToChat(Object parameter) {
TextContent += (String)parameter;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName) {
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public partial class MainWindow : Window
{
private YourViewModel _vm = new YourViewModel ();
public MainWindow()
{
InitializeComponent();
}
public MainWindow(string txtContext)
{
InitializeComponent();
_vm.TextContent = txtContext;
ClientWindow window = new ClientWindow() {DataContext = _vm};
}
private void btnMakeClient_Click(object sender, RoutedEventArgs e)
{
ClientWindow window = new ClientWindow() {DataContext = _vm};
window.Show();
}
}
public partial class ClientWindow : Window
public ClientWindow()
{
InitializeComponent();
}
}
ClientWindow xaml:
<DockPanel>
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
<TextBox x:Name="InputTextBox"/>
<Button Command="{Binding CmdAddTextToChat, Mode=OneWay}" CommandParameter="{Binding ElementName=InputTextBox, Path=Text}">
</StackPanel>
<TextBlock DockPanel.Dock="Top" Text="{Binding TextContent, Mode=OneWay}"/>
</DockPanel>
Edit: without DataContext
If you don't want to set the DataContext you can use another DP (Tag could be used, you can also create a new one):
#region ViewModelObject
public YourViewModel ViewModelObject
{
get { return (YourViewModel)GetValue(ViewModelObjectProperty); }
set { SetValue(ViewModelObjectProperty, value); }
}
private readonly static FrameworkPropertyMetadata ViewModelObjectMetadata = new FrameworkPropertyMetadata {
};
public static readonly DependencyProperty ViewModelObjectProperty =
DependencyProperty.Register("ViewModelObject", typeof(YourViewModel), typeof(ClientWindow), ViewModelObjectMetadata);
#endregion
And in your click event
private void btnMakeClient_Click(object sender, RoutedEventArgs e)
{
ClientWindow window = new ClientWindow() {YourViewModelObject = _vm};
window.Show();
}
You can create a class for message with Text property and implement INotifyPropertyChanged in this class. Then store an instance of this class in MainWindow and pass it to constructor of your ClientWindow. Set it to DataContext and create a binding to Text property (in TextBox, for example). When you update Text property the other windows will see this changes.
trying to get data from the main form to form 2. The main form has a textbox
and a button. when the button is pressed it opens form 2 which will display the data entered in the main form as a series of text blocks.
However I cant get the data to transfer between the forms. the code is bellow.
can anyone help or suggest anything I can do differently?
WPF 1 main form:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btnOpenForm_Click(object sender, RoutedEventArgs e)
{
//btnset: Takes the values contained in the text boxes and updates
//the student class
//properties.
Student.sFname = firstname.Text;
Student.sSname = secondname.Text;
Window1 details = new Window1();
details.Show();
}
WPF 2 code:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void details_Load(object sender, EventArgs e)
{
Fname.Text = Student.sFname;
Sname.Text = Student.sSname;
}
private void Close_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
There are a number of ways to "pass data" between 2 classes. The easiest way is to expose property or method on Window1 and just set the text you need passed. Another way is to create a constructor on Window1 that takes in the data as parameters. Here is code that demonstrates these approaches.
public class Program
{
public static void Main(string[] args)
{
var c1 = new Class1();
c1.DoStuff();
}
}
public class Class1
{
public void DoStuff()
{
var c = new Class2("stuff");
var c2 = new Class2();
c2.AcceptStuff("stuff2");
c.Print();
c2.Print();
c2.MyData = "stuff3";
c2.Print();
}
}
public class Class2
{
private string _myData;
public Class2()
{
}
public Class2(string myData)
{
_myData = myData;
}
public string MyData
{
set { _myData = value;}
}
public void AcceptStuff(string myData)
{
_myData = myData;
}
public void Print()
{
Console.WriteLine(_myData);
}
}
Prints
stuff
stuff2
stuff3
I assume you have a class in MainWindow like:
`Public class Student
{
public static string sFname;
public static string sSname;
}`
When you click open button you are assigning values to those variable, but if you want to access them in another window mention the window name and then class name.
Check this code if its working?
`public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void details_Load(object sender, EventArgs e)
{
Fname.Text = MainWindow.Student.sFname;
Sname.Text = Mainwindow.Student.sSname;
}
private void Close_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}`
I created two user controls which called UserControl1 and UserControl2, UserControl1 contains TextBox1 and UserControl2 contains Button1. In the UserControl2, I want to get TextBox1.Text from UserControl1 when click Button1.
This is revelant code:
In UserControl1:
public partial class UserControlA: UserControl
{
public UserControlA()
{
InitializeComponent();
}
public string TexBoxText
{
get
{
return this.textBox1.Text;
}
}
}
In UserControl2:
public partial class UserControlB: UserControl
{
public UserControlB()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//here is to get textbox1.text
}
}
What should I do?
One option is passing UserControlA instance to UserControlB's constructor.
public partial class UserControlB: UserControl
{
UserControlA userControlA;
public UserControlB(UserControlA ucA)
{
userControlA = ucA;
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string myString = userControlA.TexBoxText;
}
}
In UserControl1:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public TextBox TextBox
{
get
{
return textBox1;
}
}
}
In UserControl2:
public partial class UserControl2 : UserControl
{
private TextBox txt = null;
public UserControl2()
{
InitializeComponent();
}
public TextBox TextBox
{
set
{
txt = value;
}
}
private void button1_Click(object sender, EventArgs e)
{
if (txt != null)
MessageBox.Show(txt.Text);
}
}
In above controls' container:
uc2.TextBox = uc1.TextBox;