Access controls from a normal class (.cs) - c#

I'm working on a project and need to access a label from a normal class.cs.
NOT from the MainWindow.xaml.cs!
MainWindow.xaml: contains a Label lblTag.
Class.cs needs to execute:
lblTag.Content = "Content";
How can I realize it?
I just end up with InvalidOperationExceptions.
Window1.xaml.cs:
public Window1()
{
InitializeComponent();
[...]
}
[...]
StreamElement se1;
StreamElement se2;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
[...]
se1 = new StreamElement(this);
se2 = new StreamElement(this);
[...]
}
[...]
StreamElement.cs:
[...]
private Window1 _window;
[...]
public StreamElement(Window1 window)
{
_window = window;
}
[...]
//metaSync is called, whenever the station (it's a sort of internet radio recorder)
//changes the meta data
public void metaSync(int handle, int channle, int data, IntPtr user)
{
[...]
//Tags just gets the meta data from the file stream
Tags t = new Tags(_url, _stream);
t.getTags();
//throws InvalidOperationException - Already used in another thread
//_window.lblTag.Content = "Content" + t.title;
}
[...]

You need a reference to an instance of MainWindow class in your Class:
public Class
{
private MainWindow window;
public Class(MainWindow mainWindow)
{
window = mainWindow;
}
public void MyMethod()
{
window.lblTag.Content = "Content";
}
}
You need to pass a reference to your window instance to the class. From inside your MainWindow window code behind you would call:
var c = new Class(this);
c.MyMethod();
EDIT:
You can only access controls from the same thread. If your class is running in another thread you need to use the Dispatcher:
public void metaSync(int handle, int channle, int data, IntPtr user)
{
[...]
//Tags just gets the meta data from the file stream
Tags t = new Tags(_url, _stream);
t.getTags();
//throws InvalidOperationException - Already used in another thread
//_window.lblTag.Content = "Content" + t.title;
_window.lblTag.Dispatcher.BeginInvoke((Action)(() =>
{
_window.lblTag.Content = "Content" + t.title;
}));
}

after the edit, this seems clearer now. Damir's answer should be correct.
Just add a mainwindow object on Class.cs and pass the mainwindow's instance to the class's constructor.
on mainwindow.xaml.cs
...
Class class = new Class(this);
...
on Class.cs
...
MainWindow mWindow = null;
// constructor
public Class(MainWindow window)
{
mWindow = window;
}
private void Initialize()
{
window.lblTag.Content = "whateverobject";
}

Related

How To Set Default Window Mode to Full Screen in WinUI3?

namespace MyApp
{
public sealed partial class MainWindow : Window
{
AppWindow m_appWindow;
public MainWindow()
{
this.InitializeComponent();
m_appWindow = GetAppWindowForCurrentWindow();
}
private AppWindow GetAppWindowForCurrentWindow()
{
IntPtr hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
WindowId myWndId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hWnd);
return AppWindow.GetFromWindowId(myWndId);
}
private void SwitchPresenter_FullScreen(object sender, RoutedEventArgs e)
{
m_appWindow.SetPresenter(AppWindowPresenterKind.FullScreen);
}
}
}
SwitchPresenter_FullScreen function is works but how can i set my app's default window mode to full screen? Can i call SwitchPresenter_FullScreen while app starting?
No. Don't call SwitchPresenter_FullScreen directly. This method is for your UI controls (like CheckBox or ToggleButton).
Just add this line to your MainWindow constructor.
public MainWindow()
{
this.InitializeComponent();
m_appWindow = GetAppWindowForCurrentWindow();
m_appWindow.SetPresenter(AppWindowPresenterKind.FullScreen); // This line
}

How to make the WPF app to, open only one new window or create only single instance of the XAML, when clicking button in MainWindow?

I have a WPF application and here is the application structure:
Views
MainWindow.xaml, ABC.xaml (all with .cs files)
ViewModels
MainWindowVM.cs, ABCVM.cs
I have a Button in MainWindow.xaml (bound to MainWindowVM.cs) that calls a function, SampleFunction() in MainWindowVM.cs when being clicked and the SampleFunction() then creates a new instance of ABC.xaml (bound to ABCVM.cs) and open a new window of ABC.xaml using Show() function.
How can I make sure that clicking the Button in MainWindow would not open another new window of ABC.xaml when the old window is still there, or not create another new instance of ABC.xaml?
MainWindow.xaml.cs
public partial class MainWindow : Window
{
/*...Some other codes...*/
private MainWindowVM _VM = new MainWindowVM();
public MainWindowVM MainWindowVM
{
get { return _VM; }
set { _VM= value; }
}
public MainWindow()
{
InitializeComponent();
this.DataContext = MainWindowVM;
}
private void SomeControl_MouseLeftButtonUp(object sender,MouseButtonEventArgs e)
{
MainWindowVM.SampleFunction();
}
}
MainWindowVM.cs
public class MainWindowVM
{
/*...Some other codes...*/
public void SampleFunction()
{
ABC abc= new ABC();
abc.Show();
}
}
ABC.xaml.cs
public partial class ABC: Window
{
/*...Some other codes...*/
private static ABCVM _abcVM= new ABCVM();
public ABCVM ABCVM { get { return _abcVM; } set { _abcVM = value; } }
public ABC()
{
InitializeComponent();
this.DataContext = ABCVM;
}
}
Use ShowDialog() instead of Show().
Then you have to close the ABC.xaml first, before you can make something on the MainWindow. So you can't open a second ABC.xaml Window.
You can write code to check whether a window type object exists or not.
for each(Window win in Application.Current.Windows)
{
string windowType = win.GetType().ToString();
if (!windowType.Equals(nameSpace + "." + ABC))
{
ABC abc= new ABC();
abc.Show();
}
}

Stackoverflow Exception because of 'this.Content'?

So this sounds strange but I always get a stackoverflow exception when I execute 'this.Content' 3 times.
So I have a main window which stores all userControls so I dont have to create them always:
public partial class MainWindow : Window
{
CreateSessionWindow csw;
RateSessionWindow rsw;
CloseSessionWindow closesw;
MainMenuWindow mmw;
public MainWindow()
{
InitializeComponent();
csw = new CreateSessionWindow();
rsw = new RateSessionWindow();
closesw = new CloseSessionWindow();
mmw = new MainMenuWindow();
AllSessionWindows.csw = csw;
AllSessionWindows.rsw = rsw;
AllSessionWindows.closesw = closesw;
AllSessionWindows.mmw = mmw;
}
private void bttnStartProgram_Click(object sender, RoutedEventArgs e)
{
this.Content = AllSessionWindows.mmw;
}
}
public static class AllSessionWindows
{
public static RateSessionWindow rsw;
public static CloseSessionWindow closesw;
public static CreateSessionWindow csw;
public static MainMenuWindow mmw;
}
In my MainMenuWindow class I have a button and when I click on the button it changes the content:
public partial class MainMenuWindow : UserControl
{
public MainMenuWindow()
{
InitializeComponent();
}
private void bttnCreateSession_Click(object sender, RoutedEventArgs e)
{
this.Content = AllSessionWindows.csw; //here
}
}
And here is where I get usually the stackoverflowexception:
public partial class CreateSessionWindow : UserControl
{
public CreateSessionWindow()
{
InitializeComponent();
}
private void bttnGoBack_Click(object sender, RoutedEventArgs e)
{
this.Content = AllSessionWindows.mmw; //here I always get the exception
}
}
So no matter in which order I call this.Content (for eg. first mmw and than csw or csw and than mmw) I always get a stackoverflow Exception when I call it 3 times which you can see above. What could be the problem be?
The problem in your code is this.Content=... in UserControls (in this case this.Content is UserControl content not Window content). If you want to change content in the main window you should add property with MainWindow to class AllSessionWindows:
public static class AllSessionWindows
{
public static MainWindow MainWindow;
public static RateSessionWindow rsw;
public static CloseSessionWindow closesw;
public static CreateSessionWindow csw;
public static MainMenuWindow mmw;
}
In the MainWidnow constructor you must assign this property:
public MainWindow()
{
InitializeComponent();
...
AllSessionWindows.MainWindow = this;
}
And in UserControl you should use following code:
private void bttnCreateSession_Click(object sender, RoutedEventArgs e)
{
AllSessionWindows.MainWindow.Content = AllSessionWindows.csw;
}
Presented solution to this kind of problem by you is not the best solution. For this kind of problem, you can use Caliburn.Micro framework.
In the following link you can find a good tutorial:
http://www.mindscapehq.com/blog/index.php/2012/1/12/caliburn-micro-part-1-getting-started/
Your problem is described in part 5 and 6 of this tutorial.

Calling method from a class to a window

In WPF I got one window in which there is a button and big text block, and the class in which I got a public method which sets the text to the text block in the window. The problem is, that this doesn't work and I quite don't understand why. The code looks like this:
In MainWindow.xaml.cs
private void GoButton_Click(object sender, RoutedEventArgs e)
{
Watcher watcher = new Watcher();
watcher.StoryMode();
}
And here is the public void StoryMode from class Watcher:
string text1 = #"C:/Users/Desktop/Folder/1.txt";
string mainText;
MainWindow mw = new MainWindow();
public void StoryMode()
{
mainText = text1;
mw.textBlock_story.Text = File.ReadAllText(mainText);
}
Every time when I click on the button, nothing happen and when I try to debug, I can see that it calls the function from the Watch class, but doesn't do anything at all. When I tried same code, but outside the Watch class, inside the MainWindow like this :
private void GoButton_Click(object sender, RoutedEventArgs e)
{
string text1 = #"C:/Users/Desktop/Folder/1.txt";
string mainText;
mainText = text1;
textBlock_story.Text = File.ReadAllText(mainText);
}
All works fine, but I that's not exactly something what I want in this case.
Could somebody explain me why does this happen and how to get a better solution for this problem?
Your window class needs to create an instance of the watcher class. It should then extract the text data from the watcher class.
class Watcher
{
public string mainText;
void StoryMode()
{
mainText = "Example Text";
}
}
public partial class MainWindow : Window
{
string texblock_story_text;
public MainWindow()
{
InitializeComponent();
}
void Get_Text()
{
Watcher MyWatcher = new Watcher();
texblock_story_text = MyWatcher.mainText;
}
}

Sharing data between child and parent windows (C# WPF)

Scenario:
Three forms: MainWindow, Positions, Calibration self-named (MainWindow : Window etc.)
MainWindow creates an instance of three objects:
Vars: Model Vars = new Model();
Positions: Positions PositionsWindow = new Positions();
Calibration: Calibration CalibrationWindow = new Calibration();
A button in MainWindow is used to Show and Hide the child windows. Form fields in MainWindow update fields in class Vars.
MainWindow code:
public partial class MainWindow : Window
{
Model Vars = new Model();
Positions PositionsWindow = new Positions();
Calibration CalibrationWindow = new Calibration();
private void OpenButton_Click(object sender, RoutedEventArgs e)
{
PositionsWindow.Show();
}
private void TextBoxUpdate_Click(object sender, RoutedEventArgs e)
{
Vars.TestVar = TestBox.Text;
}
}
Question: How can form fields in the child windows update the parent form fields and/or fields in the class "Vars", i.e. passing data from child to parent and trigger an action in the parent form?
Attempts: A similar question suggested passing the main window this, example: Positions PositionsWindow = new Positions(); however, this only works when the object is created in a method. At this point, PositionsWindow.Show(); is no longer valid. i.e. it is only suitable for a child window created and closed in a single method.
I would not really recommend initializing the variables before the constructor. Don't get used to that.
I would change the constructor of each of the three Windows:
public partial class Model : Window{
MainWindow MW;
Model(MainWindow MW){
this.MW = MW;
// other constructor stuff
}
}
Do the same thing for Positions and Calibration.
Obviously, you cannot use this when you are INITIALIZING the Windows BEFORE the constructor is called, because there is still no this to pass.
Therefore, in your MainWindow:
public partial class MainWindow : Window
{
Model Vars; // = new Model(this); <- the constructor was not yet called, there is no this
Positions PositionsWindow; // = new Positions();
Calibration CalibrationWindow; // = new Calibration();
MainWindow(){
Vars = new Model(this);
Positions = new Positions(this);
CalibrationWindow = new Calibration(this);
}
private void OpenButton_Click(object sender, RoutedEventArgs e)
{
PositionsWindow.Show();
}
private void TextBoxUpdate_Click(object sender, RoutedEventArgs e)
{
Vars.TestVar = TestBox.Text;
}
}
Edit: (to complete the answer to the question):
Now, if you want the Windows to change stuff to each other, just create functions in MainWindow that change stuff in each of the Windows. And with MW you can call these functions from any child Window
For me the best is using Subscribe/Publisher event-based way, here is the way to do it. (i recreate the code so that you can understand)
1) add an event publisher in your child windows.
public partial class ChildWindows : Window
{
// the is the event publisher
public event Action<string> ChildUpdated;
public ChildWindows()
{
InitializeComponent();
}
private void updateParentBtn_Click(object sender, RoutedEventArgs e)
{
// pass the parameter.
ChildUpdated(updateTb.Text);
}
}
2) Subscribe the publisher in your parent windows.
public partial class MainWindow : Window
{
Model Vars;
ChildWindows childWindows;
public MainWindow()
{
InitializeComponent();
Vars = new Model();
childWindows = new ChildWindows();
//this is the event subscriber.
childWindows.ChildUpdated += ChildWindows_ChildUpdated;
}
//do whatever you want here.
void ChildWindows_ChildUpdated(string obj)
{
// Update your Vars and parent
Vars.TestVar = obj;
updateLbl.Content = Vars.TestVar;
}
private void openButton_Click(object sender, RoutedEventArgs e)
{
childWindows.Show();
}
private void textBoxUpdate_Click(object sender, RoutedEventArgs e)
{
}
}
3) In this case, when i type inside the textbox in my child windows, and press a button, it will appear on a label inside my parent windows.
P/S : i had changed the ParentUpdated to ChildUpdated. thanks to #Adrian for constructive feedback
example

Categories