C# Write to a RichTextBox in a Form from different classes - c#

I am using a RichTextBox which is in a Form that I am basically using as a log window whilst the program performs various functions - much like a debug window. Various methods write to the window as they perform tasks on various files. The simple class looks like this:
public partial class ValidationWindow : Form
{
public ValidationWindow()
{
InitializeComponent();
}
public void writeToWindow(string text)
{
if (richTextBoxValidationWindow.TextLength > 0)
{
richTextBoxValidationWindow.AppendText(Environment.NewLine + text);
}
else
{
richTextBoxValidationWindow.Text = text;
}
}
}
I have instantiated the Form containing the textbox from a class in the usual fashion i.e ValidationWindow valWindow = new ValidationWindow(), then call the show() method to display the window, and i can then write to it using the method in the above class called writeToWindow. All good.
I now need to be able to continue to write to the same window from other classes. I obviously don't want to create more instances of the same Validation Window. So what is the best way to do this please?

It sounds like you need access to this form from other forms and classes. In other words, you need this form to be globally accessible.
The simplest way to do this is add a global variable to your application, and save a reference to the logging window in that variable. Then, if any other class needs to log, it can access the logging window via the global variable.
However, this is perhaps not the best way to do this, as you are tying your logging to that window. What happens if you decide to log a different way? You'd have to change every reference to the window, which means changes all over the application. You would be better off looking at something like messages, which allow the calling code to send out a message requesting that something be logged, but not needing to know anything about the class that receives the message and does the actual logging. I know WOF supports this with MVVM, but am not sure how you would do it in WinForms (assuming that's what you're using). Maybe do a search on "winforms messages" and see what comes up.
Hope that helps

Related

how "intercept" messagebox & modify its content, and back to normal flow?

I have a bunch of messageboxes in an existing app, both simple informations to user and also questions.
I would like to "intercept" them (for sure not the correct IT wording), change automatically its content, and then normally display it to user.
The "OK" or other standard return should be returned/forwarded to the initial messagebox.
The modification function is a kind of translation, but for the purpose of demonstration, lets say that this special function does += " AAA" to the content and += " BBB" to the top header.
Note1: while searching, I have seen several custom message boxes, but
these are additional controls, mainly for changing the button captions
or style, not to "intercept". Please correct.
Note2: fully agree that a better & cleaner MVVM structure would have avoided the
trick needed above, but this big app started some time ago, with a
very small and different aim
As far as I know this isn't possible. You cannot have a reference to a MessageBox, so you cannot access it in any way once it is open.
According to the documentation:
You cannot create a new instance of the MessageBox class. To display a message box, call the static method MessageBox.Show.
This means that you cannot do like the following:
var box = new MessageBox([stuff]);
MS deliberately made the constructor or constructors of that class private (or protected), to make you use the factory method instead (MessageBox.Show();). Note that since they are explicitly defined, just not accessible, this means that no implicit constructor is generated either.
Doing this also won't work:
var box = MessageBox.Show([stuff]);
The Show method doesn't return a reference to the open box itself, but to the DialogResult object after it closes.
As for your situation, the only ways I can think of to solve your problem would be to either go through the program and change the strings, or create a new custom control and ditch the MessageBox entirely. You may be able to find another way, however "intercepting" the MessageBox instances isn't possible.
Assuming that the code uses System.Windows.MessageBox.Show calls using text and caption arguments, you can try defining a public static MessageBox class in a common namespace of your application providing a similar Show method that updates the arguments and calls the original MessageBox.Show method, e.g.:
public static class MessageBox
{
public static void Show(string text, string caption)
{
text += "AAA";
caption += "BBB";
System.Windows.MessageBox.Show(text, caption);
}
}
Note: this will only work if you are able to rebuild the solution from source code, as it requires adding a new source code file (the custom MessageBox class), and then rebuilding the solution.

How do I call an unreferenced method from a distant class? (C# and VB.NET allowed)

For the life of me I can't find a solution for this:
I have a class set up that does several things, one of which is manipulate wpf windows. One of these windows is the MainWindow.xaml.
So for instance I want this class to close the MainWindow.xaml, that is if for example a method is called from within OtherClass.cs.
Basically: I want to access unreferenced methods in the codebehind of a window (MainWindow.xaml.cs) from a distant class, though within the same project (Visual Studio).
When I use the MainWindow (using MainWindow or imports MainWindow in vb.net) and use its members for closing the window, as so:
using MainWindow
Public class OtherClass
{
// OtherClass is instanced elsewhere and then is decided to close MainWindow.
// So I imagine doing the following:
private void CommandClose()
{
CloseMainWindow();
}
...
}
And inside MainWindow.xaml.cs:
Public class MainWindow
{
Public void CloseMainWindow()
{
this.close();
}
...
}
Though I receive the following error: "Reference to a non-shared member requires an object reference".
Meaning I should do something like:
using MainWindow
Public class OtherClass
{
MainWindow myWindow // Though now I have a new window :/
private void CommandClose()
{
myWindow.CloseMainWindow();
}
...
}
So to access any members within MainWindow.xaml.cs and not create a new instance I need them to be shared? But that would defeat the purpose of having it do anything to the window, because the close command wouldn't be available then!
I might be overlooking some things, but atm I can't seem to notice it.
Would anyone be so kind as to show me a way to handle such a situation?
NB I am working in Windows Presentation Foundation if anyone was wondering.
To clarify further, here is a comment to one of the previous answers describing my situation:
What I am trying to do is run a command within another class, which is a public member of a WPF window. The window is already instanced and displayed. I just want to access its public members so I can manipulate the window from another class for convenience sake. This OtherClass.cs of mine is a class that handles console actions. The console is a custom control situated in the MainWindow.xaml.cs. When the user types for instance: /close, I want the MainWindow.xaml to close, but not just that, for in the future I want to add more features.
You still need an object reference. And you're gonna have to use the application context for that.
Here's how you would get a list of references to whatever type of window you have open and also close them:
var windows = Application.Current.Windows.OfType<MainWindow>();
foreach (var window in windows)
{
window.Close();
}
You could call any other method you want on them, and you can search for any other type of window, but this is how you find the one you're specifically looking for.

Get variables from list in another method?

I'm writing a webcam app and I need to write and read about 15 variables. I have two forms, the main window and the options window. When I save my options I do something like this:
string[] lines = {x , y, ..., z };
System.IO.File.WriteAllLines(#"config.cfg", lines);
In my main window I read the variables using the StreamReader function:
public void Foo()
{
List<string> lines = new List<string>();
while (!reader.EndOfStream)
{
lines.Add(reader.ReadLine());
reader.Close();
}
x = Convert.ToInt32(lines[0]);
y = Covert.ToString(lines[1]);
// and so on...
}
The problem is I don't know how to access x and y in another method. Btw: I declared all my variables as public static. Can anyone please help?
Edit
It is a windows forms app, the two windows do not exist at the same time. Maybe someone can give me a hint how to store those variables using a different method? The only thing I know I could do is store the vars using a MySQL database, but doesn't make much sense.
I'll try to clarify: what I would like to do, is pass x and y from the method Foo to another method. I can't use global variables, because reading the variables from the file requires a method.
use properties=> setting to save your values if you will need it the next time.
it's simple and help you to avoid some problems
Do both forms exist at the same time? i.e in skype you have your main skype window and your chat windows?
If so just make a CameraUpdated event, which sends the lines changed to any subscribers, then that way you can just get your main window to bind to any new child windows events, so it will be notified.
To do this you would need to make a custom event arg to pass the data, a delegate for the event name and args, and expose the actual event on your form.
If however only one form exists at a time, you could either have an in memory store you push data to and then read it out of (much like your current implementation), or when you flip from one form to the other you pass in the data that has changed.
Ultimately I would try to avoid having global style data, be it in a file, memory or a global program variable, and opt for some loosely coupled approach, but without knowing your actual implementation its difficult to advise a specific solution.
Class members that are declared as public static are accessible with:
ClassName.MemberName

what WPF method can I use to set some properties on a control's first display?

I need to store my app window's size/position and state when the user closes the app and set them back when the user thereafter opens the app.
I did this easily using registry keys (is this even the best way to do?), but I'm wondering where I actually should put the code to set those properties.
I need to set them when the window first "appears" I think. But I have several methods that could be used in this case, namely:
Window.Show()
Window.Activate()
Window.ApplyTemplate()
Window.Arrange()
Window.ArrangeCore()
Window.ArrangeOverride()
Window.BeginInit()
Window.EndInit()
Window.Measure()
Window.MeasureCore()
Window.MeasureOverride()
Window.OnApplyTemplate()
Window.OnInitialized()
Window.OnRender()
Window.UpdateLayout()
I'm aware that most of them just are a bad idea (UpdateLayout() will be called waaaaaaay too often for instance). Idealy I'm looking for a method that will only be called once in the window's life so that I don't have to add a flag checking if this is the method's first call.
so which one would be the best in this case? and why?
side question: I put the code to save the values in Window.Close() (I'm overriding the method in my MyWindow class), But I could as well have put it in Window.OnClosing() or Window.OnClosed(). Does this make any difference in my case?
side question (bis): I also have to save a datagrid's column order, where should I put both "saving" and "loading" code in this case?
Ok, it seems to me you are treating WPF like you would an old-school WinForms application. You no longer need to monitor form events to retrieve information from the Forms Properties. A majority of WPF Control properties are something known as a Dependency Property.
Amonst some of the clever things dependency properties introduce is Data Binding.
If you then consider writing the application with an MVVM Architecture you will quickly be able to work the following out yourself... =)
In the View*1, you can create either Dependency Properties, or standard properties and implement INotifyPropertyChanged, which hold the Size/Layout/Position/etc. Then bind the form's properties (in xaml or code) to the View's Properties. You can then implement any functionality you like for storing/retrieving the defaults and have automatic updates when the form is changed by simply adapting the Get/Set of the properties in the view.
As a quick example on the Windows' Title:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="{Binding Path=DisplayName}"
WindowStartupLocation="CenterScreen" >
<Grid>...</Grid>
</Window>
An example implementation of the view:
public class SampleView : System.ComponentModel.INotifyPropertyChanged
{
public event PropertyChangedEventHandler System.ComponentModel.INotifyPropertyChanged.PropertyChanged;
public delegate void PropertyChangedEventHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e);
private string _Title;
public string Title {
get {
if (_Title == null) {
_Title = My.Settings.MainWindowTitle;
}
return _Title;
}
set {
_Title = value;
if (!(_Title == My.Settings.MainWindowTitle)) {
if (PropertyChanged != null) {
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs("Title"));
}
My.Settings.MainWindowTitle = Title;
My.Settings.Save();
}
}
}
}
EDIT: Regarding how best to store user preferences, I wouldn't recommend the registry though, it's far from unheard of. The registry nowadays is packed full of settings that, in my opinion, the registry wasn't really designed for. Consider using application settings set to a user scope. That will handle most of the subleties of where and how the data is stored/retrieved and provide a nice type safe interface for you.
*1 I personally prefer to try and bind everything to the ViewModel and have almost totally dumb Views; though I do know there are plenty of valid cases for the Views having code. I wouldn't say the Size/Layout/etc is really a Business Logic Concern and isn't something I've concerned myself with up to now, so this should probably be handled in the View itself.
EDIT 2 - A quick example of User/Application scope settings:
Here is a quick picture of the settings I added to the project:
The following code attempts to use both the application and user scoped settings.
NB: Application Scope Settings are ReadOnly at runtime
public class SettingsExample
{
private Form1 frmMain = new Form1();
public void Main()
{
frmMain.BackColor = My.Settings.DefaultBackColour;
}
public void UserLoggedIn()
{
frmMain.BackColor = My.Settings.UserBackcolour;
}
public void UpdateUserBackcolour(System.Drawing.Color newColour)
{
My.Settings.UserBackcolour = newColour;
My.Settings.Save();
}
public void UpdateDefaultBackcolour(System.Drawing.Color newColour)
{
My.Settings.DefaultBackColour = newColour;
// Compiler Error
// This property is read only because it is an application setting
// Only user settings can be changed at runtime
}
}
First off, you forgot about
Loaded event - occurs when the element
is laid out, rendered, and ready for
interaction. (Inherited from
FrameworkElement.)
There is no one simple answer. Scenario may vary whether it'a child "dialog-like" window (then I would just set the size a line before Show() ), a new instance of the same window or a new instance of the app.
I will argue that UpdateLayout() is a bad idea. Actually, it's a very good idea. For example:
private bool m_onStart = true;
public MainWindow()
{
InitializeComponent();
this.LayoutUpdated += new EventHandler(MainWindow_LayoutUpdated);
}
void MainWindow_LayoutUpdated(object sender, EventArgs e)
{
if (m_onStart)
{
m_onStart = false;
Dispatcher.BeginInvoke(() =>
{
//Start App
}
);
}
}
Even if it's called a thousand time per second (which is very unlikely) you won't even notice it and won't hurt the performance.
All in all, you can make a helper method that saves user preference and second the reads it. Since the task is view related and using MVVM and binding is an overkill for this, set the size in Loaded event (do it when all ctors, initialization and visual tree is done).
My Choice: I finally ended up putting the code to load the values from the registry in window.Show().
the reason I did this is because of 2 things:
I store the state of the window, (minimized/maximized) and the way WPF does it, I need to first set the width/height, then the maximized state (if needed), otherwise it messes up the layout. And if I don't set the width/height first, I loose them when I de-maximize the window thereafter. So I have to do things in this order precisely: Width + height and them state. (Also, this is necessary when working with multiple screens, otherwise you loose the screen you were working on). This means that some of the methods above are impractical (the "measure" ones for instance)
adding to this, if I put my code in most of the methods above-mentioned, I'll get a bad looking effect on first display: the window will first appear with its height and width set, in the middle of the screen, and then after a small delay, the window gets maximized.
putting the code in window.Show() managed to solve those 2 issues. I might have had the same result with one or more of the other methods, but I simply got fed-up with trying different configurations and ended up using the first one that gave me entire satisfaction.

How do I design View logic into c# projects

I have three c# projects in my solution. One is a console app that simply calls into a class library project. The class library project does all the processing for the application. Then there is a WinForm project that displays a form and then when a button is pressed, calls the same logic in the class library project. As a result, there are two ways to run the logic, via the Console or via a Windows UI (WinForm).
My problem is that part way through the class library logic, if the UI app is being used, I want a custom WinForm form to appear to ask the user a question.
In the Console app, I want the same place in the logic to simply write out to the Console. In my understanding of architecture, you don't want the class library project to contain WinForm logic and require it to have references to all the WinForm references. But how do I make a call to the WinForms project (or something else) to display the custom WinForm form? There would be a circular reference where the class library would reference the main WinForm app and the WinForm app would reference the class library project.
What is the standard way of doing this?
You could create an interface that your library defines to communicate back to the caller, then have both your calling apps define their own implementaions of this interface, the library calls the methods on this interface and knows nothing of the implmentation.
The caller processes the methods accordingly...
public interface IProgressReporter
{
void ReportMessage(string message);
}
public class WinFormsProgressReporter : IProgressReporter
{
public void ReportMessage(string message)
{
MessageBox.SHow(message);
}
}
public class ConsoleAppProgressReporter : IProgressReporter
{
public void ReportMessage(string message)
{
Console.WriteLine(message);
}
}
public class LibraryClass
{
public static void SomeMethod(IProgressReporter rep)
{
rep.ReportMessage("Wooooohooooo!");
}
}
Why not define an inteface, IOutputHandler, that has a method called DisplayOutput. You would have 2 implementations of it, one for your winforms app and one for the console. You'd call the correct version of it at runtime. You could modify your class library to have a private field instance for the IOutputHandler, and then plug in the proper one at runtime.
You could raise an event in the class library that is listened to/registered from whatever your UI/Console layer is. That way it can decide to act on the event if it is deemed necessary in as many places as you desire. It really depends on how your architecture is setup.
This is where you need clear definition between your logic layer and your UI layer. It's perfectly acceptable and normal to put this sort of logic in your UI, since that bit can't reasonably live within the logic layer, as it is UI dependent.
Your logic should never, ever refer to any kind of UI component. If it does, it's wrong, and you need to redesign it to remove UI dependencies completely.
While the interface answers are probably better solutions, if it's just one method you could just use a delegate to pass the Console or WinForm method to the class library.
Another solution
In your class lib..
public void MyLibMethod(Action<string> callBack)
{
callBack("Yeh baby...");
}
Then call
Class.MyLibMethod(s=> Console.WriteLine(s));

Categories

Resources