I have a program with MainWindow.xaml, MainWindow.xaml.cs, and Helper.cs files. All the UI is in the .xaml file and can only be accessed from the .xaml.cs file. But now I want to change the text in a TextBox in the MainWindow.xaml file from the Helper.cs file, which is completely separate.
I've tried creating a function in MainWindow.xaml.cs to do that:
public void SetRNrInfoText(string value)
{
this.RNrInfoTextBox.Text = value;
}
or
public string RNrInfoText
{
get { return this.RNrInfoTextBox.Text; }
set { this.RNrInfoTextBox.Text = value; }
}
In Helper.cs file, I use:
public static void searchByRNR()
{
MainWindow mainWindow = new MainWindow();
mainWindow.SetRNrInfoText("new text");
}
However, when I try to call this searchByRNR function, nothing happens. In the .xaml file, "x:FieldModifier" is set to "public".
For now, the only idea I have is to make Helper return a dictionary or an array, and then in MainWindow, set all the values to certain textboxes, but I don't really like that idea.
So the question is, can I somehow change the property of a .xaml element in another .cs file, or is it not possible?"
MainWindow mainWindow = new MainWindow(); creates a new instance of the MainWindow class which is not what you want.
You need to get a reference to the already existing instance of the MainWindow in your Helper class somehow.
The easiest way to do this is probably to change the modifier of the m_window field in App.xaml.cs as suggested here.
You can then get a reference to the window in your Helper class like this:
public static void searchByRNR()
{
MainWindow mainWindow = (Application.Current as App)?.m_window as MainWindow;
mainWindow.SetRNrInfoText("new text");
}
Related
In my main window in WPF application I have a Badged element (from material design)
This is my code:
<materialDesign:Badged BadgePlacementMode="Left"
Name="RequestBadge"
Badge="3"
VerticalAlignment="Center">
<Button Content="Show Requests" ..... />
</materialDesign:Badged>
I want to change Badge content dynamically.
I add this function in code-behind:
public void setBadge(int num)
{
RequestBadge.Badge = num;
}
But when I try to call this function from other pages, I get this error:
An object reference is required for the non-static field, method, or property PL.MainWindow.setBadge(int)
you need to find an open instance of MainWindow:
var mw = Application.Current.Windows.OfType<MainWindow>().FirstOrDefault();
mw?.SetBadge(counter);
The fastest solution would be to use a singleton pattern to access your MainWindow and with this create a static method in your MainWindow that sets your badge:
private static MainWindow _instance;
public MainWindow()
{
_instance = this;
...
}
public static void SetBadge(int num)
{
_instance.setBadge(num);
}
I'm making a snake game in WPF C# and I created a few user controls for different "views", it means I have the MainWindow which
inherits from the Window class and several user controls with their xaml files.
One user control represents the main menu, another represents option view and so on.
public partial class MainWindow: Window
{
public static Menu menu;
public MainWindow()
{
InitializeComponent();
menu = new Menu();
this.Content = menu;
}
}
like above, in MainWindow I create Menu object (it's a one of the user controls - class and xaml file) and set the content of Window to content of Menu. And then in menu class I do the same, for example like user click on button with text "options", he goes to options user control. I just do
this.Content = new Options(); //"this" is now menu class
when he clicks the button with text "singleplayer", he goes to user control with singleplayer game
this.Content = new Game();
and so on.
In this way everything works fine, I can switch between different user controls and "load" different contents to application Window, but every time I create new object and it's the problem. When I go to options and then back to menu, a new object of menu class is creating, I cannot remember the previous settings and etc. I would like to create this only once and then reference to this - load existing object content. I tried using binding but it doesn't work.
Ho can I do this? How can I switch between different user controls without data loss and creating new object every time?
You should use singletons.
Singletons allow you to have only one instance of a class. This way, every time you manipulate the instance, you manipulate the same one. This allow you to keep / update the state of the same instance through your code.
It's looking like this, and it's thread safe.
public sealed class YourClass
{
private static readonly YourClass instance = new YourClass();
/* Explicit static constructor to tell C# compiler
* not to mark type as beforefieldinit */
static YourClass()
{
}
private YourClass()
{
}
public static YourClass Instance
{
get
{
return instance;
}
}
}
EDIT: OP's mistake was to set Content of the usercontrol istelf insteand of MainWindow usercontrol. You can get the current window containing usercontrol by using this line of code inside usercontrol.
Window yourParentWindow = Window.GetWindow(this);
I'm working on a multiple document viewer (a simple window with a custom control, each with a separate viewmodel). When clicking on a filename, a new instance of the user control is added to the main window. The user control has a dependency property which holds the path to the filename, defined in it's code-behind. Now i'm struck on how to get the value of this property from the user control to the viewmodel, so it can show the actual document. Any Hints?
<ctrl:DocViewerControl x:Key="docviewer" DocumentSource="{Binding SelectedItem.Path, ElementName=docList}"/>
I use this code in main window to make new instances of my user control where DocumentSource is the dependency property i need access to, as stated above.
Edit:
Following is the (relevant) code for the view and the viewmodel of my control, specific to the dependancy property value capture problem i have.
UserControl.xaml.cs
public partial class ToolboxControl : UserControl
{
public static readonly DependencyProperty DocumentSourceProperty = DependencyProperty.Register("DocumentSource",
typeof(string), typeof(ToolboxControl), new UIPropertyMetadata(new PropertyChangedCallback(OnDocumentSourceChanged)));
public ToolboxControl()
{
InitializeComponent();
}
public string DocumentSource
{
get { return (string)GetValue(DocumentSourceProperty); }
set { SetValue(DocumentSourceProperty, value); }
}
private static void OnDocumentSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
}
}
PV_ViewModel.cs
public class PV_ViewModel : ObservableObject
{
.....
public string DocumentSource
{
get { return (String.IsNullOrEmpty(_documentsource)? (_documentsource = #"about:blank") : _documentsource); }
set { SetField<string>(ref _documentsource, value, "DocumentSource"); }
}
.....
public PV_ViewModel()
{
PropertyChanged += DocumentSourceChanged;
}
.....
protected void DocumentSourceChanged(object sender, PropertyChangedEventArgs e)
{
if (sender != null)
{
switch(e.PropertyName)
{
case "DocumentSource":
{
// show the document and whatsoever
break;
}
}
}
}
.....
}
Neither the getter nor the setter of the viewmodel DocumentSource property get accessed from anywhere, despite the UserControl in MainWindow had is DocumentSourceProperty filled in with the current document path string. (i can see it form a collection of currently opened document on the main app).
To clarify: the application solution contains MainWindow project (the main view, a simple window with a TreeView and the UserControl container), the UserControl project (the (hopefully) standalone application used to show a single document when providing the path to the doc to show through the DocumentSource property.
I am not really sure I understand your problem (or if you understand how Dependency Properties work), so you may have to post a bit more of your code behind (with the DI for example)
Typically your DocViewerControl looks like this
public abstract class DocViewerControl : UserControl
{
public string Path
{
get { return (string)GetValue(PathProperty); }
set { SetValue(PathProperty, value); }
}
public static readonly DependencyProperty PathProperty =
DependencyProperty.Register("Path", typeof(string), typeof(DocViewerControl), new PropertyMetadata(string.Empty));
}
This will expose a Property in XAML of the control.
It's important here that you make it TwoWay binding, so any change from the UserControll will update the bounded field in your ViewModel.
Your ViewModel:
public class Doc1ViewModel : ViewModelBase {
private string path;
public string Path
{
get { return path;}
set {
if(path!=value) {
path = value;
OnPropertyChanged("Path");
}
}
}
}
Now, each time when you assign the property in your UserControl, the value in the ViewModel will be updated. As you can see, the Dependency Property consists from two properties. One static Dependency Property called PathProperty and one instance property called Path.
But having a closer look at it, it's not a real instance property at all. It just wraps calls around the Dependency Property by using GetValue and SetValue (which are derived from DependencyObject class, which every UI control inherits).
Hope this clears it up how Dependency Properties work, as it hard to tell what's wrong with your approach without seeing the code used.
In a nutshell, Dependency Properties (together with Attached Properties) extend the XAML code with TwoWay bindable properties (normal instance property can only be bound in one direction).
I want to assign a value right when initializing a new UserControl:
public partial class MyUserControl : UserControl
{
public MyUserControl(int id)
{
InitializeComponent();
//.. do something with id
}
// ...
}
Is it possible to pass a value to constructor (id in my case) from xaml?
<CustomControls:MyUserControl />
(Yes I can define a dependency property or make the control in code behind, but that doesn't help)
Yeah, that's possible. You can create a user control programmatically. Then, you can use any constructor you want. Here's a sample:
Supposing, that we have a usercontrol, that assigns a value to textbox on initialization:
public ControlWithP(int i)
{
InitializeComponent();
tb.Text = i.ToString();
}
Add this control to page:
public SamplePage()
{
InitializeComponent();
ControlWithP cwp = new ControlWithP(1);
this.sp.Children.Add(cwp);
}
where sp is StackPanel control. Same thing with adding user control to Grid.
see the result.
Is this, what you wanted?
From XAML-2009 you could do this with x:Arguments Directive but Windows Phone is using 2006 (for now) so it is not possible.
So to use your control from XAML you need a default contructor (parameterless).
I think you could use a little workaround, by using specially designed property for this:
public partial class MyControl : UserControl
{
private string myValue = "Default";
public string MyValue
{
get { return myValue; }
set
{
myValue = value;
// alternatively you can add some code here which
// will be invoked after control is created
}
}
public MyControl()
{
InitializeComponent();
}
}
then in XAML:
<local:MyControl MyValue="From xaml"/>
Just after the control is created, the property is set and its code invoked - so it can alternatively be used as additional part of code run during creation.
If you want to pass data to your control, better choice would be DependencyProperty - example here.
There is one MainWindow and one user-control in my WPF application. I want to call function of my MainWindow in user-control, without creating new instance of MainWindow. For this i made main-window parent of user-control. I wrote this code below for calling function of Parent.
Child User-Control
public partial class AppLogo : UserControl
{
public MainWindow myparent { get; set; }
private void activate_Click_1(object sender, RoutedEventArgs e)
{
myparent.function();
}
. . .
}
Parent Window:
public MainWindow()
{
InitializeComponent();
AppLogo childWindow = new AppLogo();
. . .
Questions:
Is It Possible to create Window a parent of user-control?
If answer of above question is Yes then why it is generating error that Object Reference is Null.
If answer is No it is not possible then how can i achieve this goal. As it is necessary to create user-control in my application as it is requirement.
If you want to have reference in UserControl to MainWindow use following code:
MainWindow mw = Application.Current.MainWindow as MainWindow;
http://msdn.microsoft.com/en-us/library/system.windows.application.mainwindow.aspx
private void activate_Click_1(object sender, RoutedEventArgs e)
{
MainWindow mw = Application.Current.MainWindow as MainWindow;
if(mw != null)
{
mw.function();
}
}
Second solution:
In your code you should set myparent property in MainWindow constructor:
public MainWindow()
{
InitializeComponent();
AppLogo childWindow = new AppLogo();
childWindow.myparent = this;
...
}
In activate_Click_1 event handler the good habit is check if myparent is not null:
private void activate_Click_1(object sender, RoutedEventArgs e)
{
if(myparent != null)
myparent.function();
else
...
}
I'm assuming that the null reference is for the myparent property on AppLogo?
After this line AppLogo childWindow = new AppLogo(); add one saying childWindow.myparent = this;
You may introduce a child parent dependecy as suggested, however since you didn't instantiate MainWindow you should expect a null reference exception when calling myparent.function();
First, you need to instantiate MainWindow, and then set the child parent relationship by calling AppLogo .set_myparent, only then your call won't fail.
You need to pass a reference to the instance of MainWindow as an argument to AppLogo's constructor, then set it to AppLogo's variable for MainWindow.
public AppLogo(MainWindow mainWindow)
{
this.myparent = mainWindow;
}
If you locate your UserControl directly inside your Window, then its Parent property will reference your window.
The exception is called when you try to access the field which contains null value. It contains null because noone placed there anything else. You might want to set it:
AppLogo childWindow = new AppLogo();
childWindow.myparent = <something>;
You just need to recursively search your UserControl's parents until you get an instance of a Window, which will be your goal.
public static Window GetWindow(FrameworkElement element)
{
return (element.Parent as Window) ?? GetWindow(element.Parent);
}