I'm using Visual Studio 2015 and .Net
I’ve come upon a somewhat peculiar problem. I have a C# solution with two projects. One is a standard WPF application, the other a WPF User Control library. The WPF application project is the startup project.
In each project I have one window. In the startup project I open the window and set a value in the logical call context by using CallContext.LogicalSetData. This is done on load. I then close the window and open the window in the WPF User Control library. I populate one textbox with the value in the logical call context (using CallContext.LogicalGetData) and this works fine.
I have a button, which on click fires an event that populates another textbox with the same value from the logical call context – but all of a sudden this value is null.
I can make it work simply by changing the starting window to not do it’s “thing” on load but rather on a button event.
The startup window code:
public partial class MainWindow : Window
{
public MainWindow()
{
this.Loaded += OnLoaded;
InitializeComponent();
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
CallContext.LogicalSetData("test", "value set onload");
TestWindow win = new TestWindow();
win.Show();
this.Close();
}
private void button_Click(object sender, RoutedEventArgs e)
{
CallContext.LogicalSetData("test", "value set on button event");
TestWindow win = new TestWindow();
win.Show();
this.Close();
}
}
As mentioned above, if I comment out the four lines in the OnLoaded method then it works fine.
The other window:
public partial class TestWindow : Window
{
public TestWindow()
{
InitializeComponent();
PreLoadedText.Text = CallContext.LogicalGetData("test") as string;
}
private void GetValue_Click(object sender, RoutedEventArgs e)
{
string eventTextText = CallContext.LogicalGetData("test") as string;
EventText.Text = eventTextText ?? "The value is null";
}
}
Btw. I tried using the AsyncLocal<T> class - but I just experienced the same problem.
Example solution can be found here:
Visual studio solution as zip file
Note - I'm not looking for a workaround (I have a couple), I'm looking for a reason why this happens.
It's because the instance of Thread.CurrentThread.ExecutionContext, which contains the DataStore of the CallContext, changes between the calls. You can check that if you give it a marker by using "Make Object ID" in the Visual Studio debugger.
Why does this happen? I have absolutely no idea. I tried to debug the .net Framework source without any luck.
As far as AsyncLocal<T> is concerned: It also uses the same Thread.CurrentThread.ExecutionContext and thus suffers from the same problem.
It doesn't happen if you use ThreadLocal<T> because that's using [ThreadStatic] and the Thread itself doesn't change.
Related
So I'm still learning how to do C# applications and I have actually a problem with a window.
I've created a WPF project and I've separated some part of my main window in sub-parts (user-controls) so I can have a cleaner xaml code to work with.
I have a lot of different UserControl such as UserControlMenuStrip. All of them are inside the MainWindow.
Inside the MenuStrip was a MenuItem called Parameters :
<MenuItem Header="_Parameters" x:Name="MenuParameters"/>
I have created a new window called ParametersWindow. My goal was to open a child window centered with the main window when I click on the item.
But I don't really know how to proceed? Should I make a click= event and write down the code inside the linked UserControlMenuItem.xaml.cs linked file? Or in the MainWindow.xaml.cs file? Or maybe a new and clean file?
When I try to put it inside UserControlMenuItem.xaml.cs, I can't properly set the owner of the window I create this method but I can't set the owner:
private void OpenParametersWindow()
{
WindowParameters WinParam = new WindowParameters();
WinParam.Owner = MainWindow();
WinParam.WindowStartupLocation = WindowStartupLocation.CenterOwner;
WinParam.Show();
}
And, when I try via the MainWindow.xaml.cs I can't even get the variable...
So... How can I properly open the Window properly? And should I do it in the xaml.cs file or create a new one for a better understanding?
I've Created a class and added a static field as MainWindow to holding reference
class ReferenceClass
{
public static MainWindow mainWindow = null;//firstly null.we will set it in WindowLoaded event.
}
You can create a class like this for accessing reference of your MainWindow from wherever you want.Give your MainWindow reference to its static field.
MainWindow Loaded Event
private void Window_Loaded(object sender, RoutedEventArgs e)
{
ReferenceClass.mainWindow = this; //setting the reference to static field of ReferenceClass.
}
Menu Click (Event called on MenuStrip UserControl)
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
NewWindow nw = new NewWindow();
nw.Owner = ReferenceClass.mainWindow;//Calling the reference of MainWindow from our class.
nw.WindowStartupLocation = WindowStartupLocation.CenterOwner;
nw.Show();
}
Here we go
Project
This is just a way for solving this issue.We can find more solutions which are better than mine but i use this solution when i need.
A handle to the parent window for any usercontrol can be obtained that way:
Window wndParent = System.Windows.Window.GetWindow(this);
WinParam.Show(wndParent);
But when working with WPF, it is more convenient to use the MVVM pattern
As you writing UI in WPF it is preferred to implement it with MVVM pattern. It allows you to have a clear separation of concerns between code and presentation.
Regarding your question about how to set Owner I suggest reading this series of articles about dialogs in WPF implemented with MVVM in mind
https://www.c-sharpcorner.com/article/dialogs-in-wpf-mvvm/
I've been working in WPF and trying to start a Winform from that area. The only solution is to open it as a ShowDialog(). Is this a bug or can we expect any problems in the future?
my other program is located in the same solution, but not the same namespace.
WindowsFormsApplication1.Form1 program2 = new WindowsFormsApplication1.Form1();
program2.ShowDialog();
I've just tested this, and it works for me:
public partial class MainWindow : Window
{
private Form winForm;
public MainWindow()
{
InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
winForm = new WinForm1();
winForm.Show();
}
}
I believe your problem is most likely due to your program2 going out of scope immediately after you try to call Show on it, which is closing it faster than you can see it. The reason ShowDialog works, is because it is a blocking call, keeps the window in scope and open until after it is closed.
Try declaring program2 as a field within the WPF Window class, instead of as a local variable. That will keep it in scope.
I found the problem... the reason program2.Show() was not working was becouse of Cefsharp during the launch of the second program via javascript the loading progress bar(Javascript) was not done loading. you can identify these problems with Cefsharp by tagging them in to
if (browser.CanExecuteJavascriptInMainFrame)
{
WindowsFormsApplication1.Form1 program2 = new WindowsFormsApplication1.Form1();
program2.Show();
}
I've got two WPF windows and I want to do this: when user clicks on a button, which is located in the first window, a second window will open and in this window the user will click for example on button "Sword". Then in first window's textblock, text will show "Sword" immediately.
I know I can transfer text or string with text file or XML file or class. But I don't know how to do it immediately. Should I use timer or is there another way?
Thanks for reply.
The simpiliest way is to pass first window as a parameter to the constructor of the second window and change properties of first one on the button click event handler.
public class SecondWindow : Window
{
private readonly FirstWindow _owner;
public SecondWindow(FirstWindow owner)
{
_owner = owner;
}
private void OnSwordButtonClick(object sender, EventArgs e)
{
_owner.TextBlockValue = "New value";
}
}
You can use more commplex and universal solution with EventAggregator or other event-based patterns. Event aggregator helps to implement subscriber/publisher pattern in low-coupled app.
First create new event with property that you want to send between components (or without any properties if there is no data in this event).
Next subscribe first window to your event and change your data (string binded to the Label or other model property) in event handler with parameter received from handler parameter.
Finally raise (or publish in other terms) your event from your second window on button click event handler.
As you can see both of implementations is a part of MVVM libraries and this pattern can be useful for your app.
EDIT
Your code examples shows a problem with NullReferenceException. It happens because you are calling Window1 constructor in the wrong manner. I write full example below but try to repeat again with more details. Change your code to the next one:
public class Window1 : Window
{
private readonly MainWindow _owner;
// The only constructor of Window1 class
public Window1(MainWindow owner)
{
InitializeComponent();
_owner = owner;
}
private void button_Click(object sender, RoutedEventArgs e)
{
_owner.TbW1.Text = "Sword1";
}
}
public class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e)
{
// create new instance of Window1 and pass current window as a constructor parameter
var win1 = new Window1(this);
win1.Show();
}
}
Also, there are many recommendations for you.
It's better to use sensible class/method/variable names for example OptionsWindow instead of Window1 OnChooseSwordButtonClick() instead of button_Click. Read more about Naming Guidelines on MSDN.
Read more about C# Coding Conventions on MSDN.
Read more about NullReferenceException.
The term you are looking for is Interprocess Communications (IPC).
Here is an excerpt from Microsoft:
The Windows operating system provides mechanisms for facilitating
communications and data sharing between applications. Collectively,
the activities enabled by these mechanisms are called interprocess
communications (IPC). Some forms of IPC facilitate the division of
labor among several specialized processes. Other forms of IPC
facilitate the division of labor among computers on a network.
I'm fairly new to Visual C# and I'm writing an GUI app with multiple forms. One form is main window, and the rest are some kind of option windows. When showing an option window, I need to load some data to it (for example a string to window's editbox), then edit it and return back to main window when closing option window. Is there any simple way I can achieve it?
I've found some solutions like, or c# event handling between two forms, but I can't really conform it to my needs. I was thinking about passing data in constructor, but how to get it back? I've found something about ShowDialog, but as I said I'm new to C# (started yesterday ^^) and don't know if I can use it.
Any ideas, please?
I found the following previous answer which outlines sending specific properties from the one form to another:
Send values from one form to another form
The using keyword will also ensure that the form is cleaned-up properly, here's a link to it's usage (pardon the pun...) : http://msdn.microsoft.com/en-us/library/vstudio/yh598w02.aspx
I've run into the same issue to be honest, and I have to say that prior to this discussion I would just pass the parent form itself to the child and alter it in that way. Such as:
ChildForm child = new ChildForm(this); //from the parent
and
public ChildForm(ParentForm parent)
{
this.parent = parent;
}
Probably not the best convention though, as you probably don't need to access that much from the parent as the child.
Thanks guys, I think I finally get it. Idle_Mind, your idea was the easiest in my point of view, so I decided to use it. If someone else has a problem like this, here's what I've coded:
In main window form: when button is clicked, a new form appears; after closing it, label1 shows the text typed in that form
private void Button1_Click(object sender, EventArgs e)
{
LoadDataForm loaddata = new LoadDataForm("initial value");
if (loaddata.ShowDialog() == DialogResult.OK)
{
label1.Text = loaddata.textBox1.Text;
}
}
In load data form: argument passed in form's constructor appears in textBox1; textBox1's Modifiers property has to be modified to "public"
public LoadDataForm(string initvalue)
{
InitializeComponent();
textBox1.Text = initvalue;
}
private void ApplyButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
Regards,
mopsiok
I have a WPF window in a project with a XAML file and associated C# code behind file. If I set "StartupUri=MainWindow.xaml" in App.xaml to this window the window opens as expected when I start my application.
However, I want my application to to take command line parameters and then decided if it should open the GUI or not. So instead I've set "Startup=Application_Startup" in my App.xaml file which is defined as shown below.
private void Application_Startup(object sender, StartupEventArgs e)
{
if (e.Args.Length > 1)
{
//do automated tasks
}
else
{
//open ui
MainWindow window = new MainWindow();
this.MainWindow = window;
window.Show();
}
}
Yet when I run this the window displayed is totally blank.
Adding window.InitializeComponent() seems to do the trick:
MainWindow window = new MainWindow();
Application.Current.MainWindow = window;
window.InitializeComponent();
window.Show();
I usually like to have a little explanation on why something does or doesn't work. I have no clue in this case. I can see that the examples online don't include InitializeComponent, and yet I produce the same exact error as you do (event without checking for args).
I created a sample application, and removed the StartupUri and set the Startup to the method you provided. Everything seems to work as expected, the content of the window is displayed, so maybe, as Daniel mentioned, you're missing the call to InitializeComponent method in your MainWindow constructor.