C# and WPF: controls inaccessible from another class - c#

I just started fiddling around with C# and WPF.
Let's say that I want to instantiate a Black grid and that I want to randomly move around a red square in said Grid.
Currently I can basically do whatever I want as long as I keep everything in "MainWindow.xaml.cs"...
Now, my problem is that if I create a new class (e.g., "MakeStuffHappen.cs") and from it I try to access the Grid (named "MyGrid") that will be instantiated by MainWindow's constructor, intellisense doesn't "see" it.
I tried making a getter that returns "MyGrid" but then the compiler says that "an object reference is required for the non-static field, method, or property 'ProjectName.MainWindow.getGrid()'.
Obviously I cannot define MainWindow as a static class...
Any tips on how to solve this?
Thanks!
P.S. Since I'm evidently no programmer I'm not necessarily aware of the technical terms to use when looking up information... so I apologize in advance if this question has been already asked.
P.P.S. I saw this: Access MainWIndow Control from a class in a separate file but it doesn't help.

Once your view is initialized (when the OnInitialized event fires) you can pass the initialized Grid into your helper class:
MainWindow.xaml.cs:
public partial class MainWindow
{
MakeStuffHappen helper = null;
public MainWindow()
{
OnInitialized += (s,e)=> { helper = new MakeStuffHappen(this.MyGridName); }
}
}
MakeStuffHappen.cs
public class MakeStuffHappen
{
Grid theGrid = null;
public MakeStuffHappen(Grid grid)
{
theGrid = grid;
// Do stuff with the grid.
}
}

Related

How do I use a variable outside of a partial class?

I'm new to C#, and I'm new to the idea of "partial" classes.
I wish to access the "grid" variable outside of this "MainWindow" class. How would I go about doing that?
Partial means that your class is split among different files, it has nothing to do with the exposure of variables to other classes.
Your grid is a local variable in your current method, so it's not accessible by others. If you want to make it accessible, define it as a property instead.
public DataGrid Grid { get; set; }
Even though it is technically possible, you should not make your data grid accessible outside the class. The grid is part of the view managed by your class, so making the grid accessible to other classes breaks encapsulation by making implementation details of your form visible.
I have another class, Server, and it receives data that I wish to add to grid.ItemSource.
Then your Server class should provide a data source to which your form should bind the grid. In other words, the access should go in the other direction.
You need to declare the variable as a public member of the class like this
public partial class MainWindow ...
{
public DataGrid grid;
public MainWindow()
{
...
}
public void DataGrid_Loaded(...)
{
...
grid = sender as DataGrid;
...
}
}
Now you can access to the variable in this way
var x = MainWindow.grid;

WPF call method parent from usercontrol

I want to call a method from user control in WPF
I´ve a Window with a list and I have a method that get this list.
private ObservableCollection<int> _lst;
public MainWindow()
{
InitializeComponent();
getList();
}
public void getList()
{
_lst = List<int>();
}
In this page I use a usercontrol:
UserControlAAA userControl = new UserControlAAA ();
gridDatos.Children.Add(userControl);
I want to do something like this inside of usercontrol:
Window win = Window.GetWindow(this);
win.getList();
but I can´t call win.getList();
I want to call the method getList from my usercontrol, but I don´t know how to do it.
You'll need to cast the Window object to the specific window type you're using - which in your case is MainWindow:
MainWindow win = (MainWindow)Window.GetWindow(this);
win.getList();
However, it's not wise to have such coupling between the user control and the window it's hosted in, since that means you will only be able to use it in a window of type MainWindow. It would be better to expose a dependency property in the user control and bind the list to that property - this way the user control will have the data it requires and it will also be reusable in any type of window.
Solution from #Adi Lester is working but it break WPF coding ruler. Proper way of doing this is using event like in the linked answer below
https://stackoverflow.com/a/19384953/3099317

How can I access a control in WPF from another class or window

I want to access my controls like button or textbox in mainWindow in WPF, but I can't do this.
In Windows Form application it's so easy, you can set modifier of that control to True and you can reach that control from an instance of that mainWindow, but in WPF I can't declare a public control. How can I do this?
To access controls in another WPF forms, you have to declare that control as public. The default declaration for controls in WPF is public, but you can specify it with this code:
<TextBox x:Name="textBox1" x:FieldModifier="public" />
And after that you can search in all active windows in the application to find windows that have control like this:
foreach (Window window in Application.Current.Windows)
{
if (window.GetType() == typeof(Window1))
{
(window as Window1).textBox1.Text = "I changed it from another window";
}
}
Unfortunately, the basics of WPF are data bindings. Doing it any other way is 'going against the grain', is bad practice, and is generally orders of magnitude more complex to code and to understand.
To your issue at hand, if you have data to share between views (and even if it's only one view), create a view model class which contains properties to represent the data, and bind to the properties from your view(s).
In your code, only manage your view model class, and don't touch the actual view with its visual controls and visual composition.
I found that in WPF, you have to cast Window as a MainWindow.
Looks complicated but it's very easy! However, maybe not best practices.
Supposing we have a Label1, a Button1 in the MainWindow, and you have a class that deals with anything related to the User Interface called UI.
We can have the following:
MainWindow Class:
namespace WpfApplication1
{
public partial class MainWindow : Window
{
UI ui = null;
//Here, "null" prevents an automatic instantiation of the class,
//which may raise a Stack Overflow Exception or not.
//If you're creating controls such as TextBoxes, Labels, Buttons...
public MainWindow()
{
InitializeComponent(); //This starts all controls created with the XAML Designer.
ui = new UI(); //Now we can safely create an instantiation of our UI class.
ui.Start();
}
}
}
UI Class:
namespace WpfApplication1
{
public class UI
{
MainWindow Form = Application.Current.Windows[0] as MainWindow;
//Bear in mind the array! Ensure it's the correct Window you're trying to catch.
public void Start()
{
Form.Label1.Content = "Yay! You made it!";
Form.Top = 0;
Form.Button1.Width = 50;
//Et voilá! You have now access to the MainWindow and all it's controls
//from a separate class/file!
CreateLabel(text, count); //Creating a control to be added to "Form".
}
private void CreateLabel(string Text, int Count)
{
Label aLabel = new Label();
aLabel.Name = Text.Replace(" ", "") + "Label";
aLabel.Content = Text + ": ";
aLabel.HorizontalAlignment = HorizontalAlignment.Right;
aLabel.VerticalAlignment = VerticalAlignment.Center;
aLabel.Margin = new Thickness(0);
aLabel.FontFamily = Form.DIN;
aLabel.FontSize = 29.333;
Grid.SetRow(aLabel, Count);
Grid.SetColumn(aLabel, 0);
Form.MainGrid.Children.Add(aLabel); //Haha! We're adding it to a Grid in "Form"!
}
}
}
var targetWindow = Application.Current.Windows.Cast<Window>().FirstOrDefault(window => window is principal) as principal;
targetWindow .BssAcesso.Background = Brushes.Transparent;
just call any control of it from your current window:
targetWindow.ABUTTON.Background = Brushes.Transparent;
How can I access one window's control (richtextbox) from another window in wpf?
I was also struggling with this when I started WPF. However, I found a nice way around it similar to the good old fashioned win forms approach (coding VB.NET, sorry). Adding on what was said earlier:
To directly change properties of objects from a module or a different class for an active window:
Public Class Whatever
Public Sub ChangeObjProperties()
' Here the window is indexed in case of multiple instances of the same
' window could possibly be open at any given time.. otherwise just use 0
Dim w As MainWindow = Application.Current.Windows(0)
w.Button1.Content = "Anything"
End Sub
End Class
You obviously have to instantiate Whatever before ChangeObjProperties() can be called in your code.
Also there is no need to worry about naming in XAML regarding object accessibility.
Just declare your control like this to make it public:
<TextBox x:Name="textBox1" x:FieldModifier="public" />
You can then access it from another control.
The default declaration of controls is non public, internal and not public!
Access of the controls from within the same assembly is hence allowed. If you want to access a control on a wpf form from another assembly you have to use the modifier attribute x:FieldModifier="public" or use the method proposed by Jean.
This may be a slightly different answer, but let's think about why we need to pass data between forms.
obviously, the reason is 'visualization'.
use Delegate or Event.
There is no need to declare an element as Public just to make it visible.
only need to be able to transform elements within a window using a delegate , on a limited basis.
To access any control in another window is so simple. Lets say to access from a Login window to MainWindow. Here is the steps:
MainWindow MW = new MainWindow(); //declare the mainwindow
MW.Label1.Content = "Hello world"; //specify what control
MW.ShowDialog(); //check what happen to that control
Good programming

Why do I get an error in the MainWindow when trying to initialize a textbox in a UserControl

I created a UserControl that contains a textbox. When I try to initialize the textbox in the constructor of the UserControl, with some text like this
public FileSelector()
{
InitializeComponent();
TB_FolderPath.Text = #"c:\tmp\Test\";
}
I get an error in the MainWindow.xaml
Cannot create an instance of "FileSelector".
When I remove the row
TB_FolderPath.Text = #"c:\tmp\Test\";
I don't get the error, but of course an empty textbox.
Previously when I had the parts of the UserControl integrated in the MainWindow, there was also no problem.
I tried to create a simpler version of MainWindow using a UserControl to reproduce the problem, but in a simple case it works.
So, my questions.
What can be the cause of the problem?
How can I debug/analyze a problem like this systematically? I just get the this error in VisualStudio after building, without an explanation.
How/Where can I initialize the controls in a UserControl. In general, is the UserControl the right place to initialize the controls or would the MainWindow be also a possibility? (Is this possible at all?)
In WPF, unlike WinForms, the controls are not initialized completely after InitializeComponent(). Hence the uninitialized/unloaded controls throw errors.
You need to write handler to capture the Loaded event of the control.
Read Object Lifetime Events.
Get some more detailed info here.
Example (partially taken from OP's code):
public FileSelector()
{
InitializeComponent();
TB_FolderPath.Loaded += delegate { TB_FolderPath.Text = #"c:\tmp\Test\"; }
}

extend a user control

I have a question about extending a custom control which inherits from UserControl.
public partial class Item : UserControl
{
public Item ()
{
InitializeComponent();
}
}
and I would like to make a control which inherits from Item
sg like that
public partial class ItemExtended : Item
{
public ItemExtended():base()
{
InitializeComponent();
}
}
This works perfectly of course and the heritage works but my problem is in the designer
I just cannot open this ItemExtended in Design....
it says : Constructor on Type "Item" not found.
Does sy have an explanation?
is the best way to do it?
Thx
I'm of course using c# on .NET Winform :)
you invoke InitializeComponent() twice with calling InitializeComponent() on the very derived usercontrol.
This may lead to problem.
And there is some help property callad IsDesign or Design (something similar) of UC, which helps to avoid unnecessary UI operations on design time (in VS).
Edit: it is DesignMode. You can avoid to run RT functions by Design. Like if (!this.DesignMode) InitializeComponents();
You can also check this forumpost. http://www.c-sharpcorner.com/Forums/ShowMessages.aspx?ThreadID=41254

Categories