Get ClassName of a Window from Window Reference - wpf

I have a Window partial class (WPF Window) like:
public partial class MyWindow : Window
{
// this is just a WPF window
// I have in XAML Closing event like Closing="Window_Closing"
// and here is the event definition
public void Window_Closing(object sender, CancelEventArgs e)
{
SaveWindowState(this); // just passes reference to itself
}
}
In another assembly, I have logic which receives reference passed in above like this
public static void SaveWindowState(Window window)
{
// Since I can call this from many windows, I need a way to get
// the class name of my window in here. Basically, for MyWindow
// above, I need to get "MyWindow" and for other windows, I need
// to get thier class name from the passed in "window" parameter.
}
How do I get the actual class name for the passed in Window?

Simply window.GetType().Name?

Related

Using callback interface as a DependencyProperty in WPF?

I apologize for the lengthy question, but I feel like it is necessary to include all of this information.
Until now, I've been using a possibly-unorthodox way of adding UserControls to my applications. Let's say I have a UserControl called Diagnostics that has a button, that when clicked, performs a function that is specific to the application that owns it. For example, if I drop Diagnostics into AppA, I want it to display "A", and if I drop it into AppB, I want AppB to define the behavior so it displays "B".
I typically implement this via a callback interface that is passed to the UserControl's constructor, which is pretty straightforward. Here's some sample "code" that probably won't compile, but is presented just to clarify what I've basically done before, and what I am trying to do:
public interface IDiagnosticsCallback {
void DisplayDiagnostics(); // implemented by owner of Diagnostics UserControl
}
public class MyApp : IDiagnosticsCallback {
public void DisplayDiagnostics() {
MessageBox.Show("Diagnostics displayed specifically for MyApp here");
}
}
public Diagnostics : UserControl {
private IDiagnosticsCallback _callback { get; private set; }
public Diagnostics(IDiagnosticsCallback callback) {
_callback = callback;
}
public void ShowDiagnostics_Click(object sender, EventArgs e) {
_callback.DisplayDiagnostics();
}
}
The problem I had in the past was understanding how to declare a UserControl that takes a parameter in its constructor (i.e. doesn't have a default constructor) in XAML, and apparently you can't. I worked around this with a fairly-inelegant method -- I would give the main panel a name in XAML, and then from code-behind I would create Diagnostics, passing it the necessary callback, and then I would add Diagnostics to the panel's list of children. Gross and violates usage of MVVM, but it works.
This weekend, I decided to try to learn how to do it for a class and a TextBox, and it turns out that all I had to do was to create a DependencyProperty in my UserControl and use databinding. It looks something like this:
public ClassA
{
public void ShowSomethingSpecial()
{
MessageBox.Show("Watch me dance!");
}
}
public MyApp
{
public ClassA Foo { get; set; }
}
public Diagnostics : UserControl
{
public static readonly DependencyProperty SomethingProperty = DependencyProperty.Register("Something", typeof(ClassA), typeof(Diagnostics), new PropertyMetadata());
public ClassA Something
{
get { return (MyApp)GetValue(SomethingProperty); }
set { SetValue(SomethingProperty, value); }
}
// now uses default constructor
public void ShowSomethingSpecial_Click(object sender, EventArgs e)
{
Something.ShowSomethingSpecial();
}
}
MyApp.xaml
<diags:Diagnostics Something="{Binding Foo}" />
So Foo is a property of MyApp, which is databound to the Something DependencyProperty of Diagnostics. When I click the button in the UserControl, the behavior is defined by ClassA. Much better, and works with MVVM!
What I'd like to do now is to go one step further and instead pass a callback interface to my UserControl so that it can get the states of my digital inputs and outputs. I'm looking for something like this:
public Diagnostics : UserControl
{
public interface IDioCallback
{
short ReadInputs();
short ReadOutputs();
void SetOutput( char bit);
}
public IDioCallback DioCallbackInterface {
get { return (IDioCallback)GetValue(DioCallbackInterfaceProperty); }
set { SetValue(DioCallbackInterfaceProperty,value); }
}
// Using a DependencyProperty as the backing store for DioCallbackInterface. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DioCallbackInterfaceProperty = DependencyProperty.Register("DioCallbackInterface",typeof(IDioCallback),typeof(Diagnostics),new PropertyMetadata(0)); // PropertyMetadata is the problem...
}
public class DIO : IDioCallback
{
public short ReadInputs() { return 0; }
public short ReadOutputs() { return 0; }
public void SetOutput( char bit) {}
}
public class MyApp
{
public DIO MyDIO { get; set; }
}
MyApp.xaml
<diags:Diagnostics DioCallbackInterface="{Binding MyDIO}" />
While my code (maybe not the exact code above, but my real project) does compile successfully, it appears that the PropertyMetadata passed to Register is at fault. I get an exception that says "Default value type does not match type of property 'DioCallbackInterface'."
Am I doing something really unorthodox, or is this approach to databinding interfaces actually possible? If not, what are the recommended ways of defining how a UserControl behaves based on the application it's being used in?
The exception you have mentioned because of this:
new PropertyMetadata(0)
You have passed 0 (of type Int32) instead of the null or whatever you like for your interface: IDioCallback.
I cannot say that the way you select is wrong, but you should keep in mind that every user of your UserControl must implement that interface you have defined. If you have several properties that you would like to pass to the UserControl, you can basically discard them via DependencyProperty.
In your case you also would like to inject some logic to the UserControl Button. Let me suppose that this control has only one button. MVVM-way to handle Button.Click event is done via ICommand - you can declare the command property in your ViewModel and use it as data source for data binding in your UserControl as DependencyProperty, passing it properly to the Button.
Also you can have an agreement with all of your data context, and use special name for that property. For example:
public interface IViewModelWithCommand
{
public ICommand TheCommand { get; }
}
Implement it for each data context you need, and use TheCommand property name inside your data template of your UserControl. In the code-behind you can create type validation of DataContext passed to your UserControl, and throw an exception in case the type is not implements your interface
Here several articles you probably should be interested in:
RelayCommand
Commands, RelayCommands and EventToCommand
How to use RelayCommands
Using RelayCommand will simplify your life because you don't need to re-implement interface for every command, instead, you need to pass valid action that you want.

Modify property of MainWindow from UserControl

I am creating a UserControl, I want that when I click in a button from that Control a property (attriibute) modifies from my MainWindow. The UserControl is created from a separate project and built as a .dll.
I had tried the following:
Window l = Window.GetWindow(this);
The problem is that because my window is not being referenced I have no way to access it (the properties I had created) and I dont know how to do it. If I try to write "MainWindow" it says that it couldn't be found.
You can get window using Application.Current.MainWindow. It will return window object so make sure you typecast it to actual instance of your window.
Assuming actual instance is MainWindow, it can be accessed like this:
MainWindow window = (MainWindow)Application.Current.MainWindow;
You have a number of ways of accessing a reference to the main Window in WPF. There is the way that #Rohit Vats showed you:
MainWindow window = (MainWindow)Application.Current.MainWindow;
However, as you have noticed, this does not always work. Sometimes it can be fixed simply by setting the property to the MainWindow instance:
public MainWindow()
{
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Application.Current.MainWindow = this;
}
You should now be able to access the MainWindow from this property. However, if that still doesn't work for some reason, then you can also try the Application.Windows property:
foreach (MainWindow window in Application.Windows.OfType<MainWindow>())
{
// Do something with window here
}

WPF shortcut in whole window

I'm developing MVVM application and I'd like to create global shortcuts for my application. It's necessary to navigatate application between modules. I have main window with code:
<UserControl.InputBindings>
<KeyBinding Command="{Binding ChangeModuleComand}"
Key="M"
Modifiers="Control"/>
</UserControl.InputBindings>
It works when I have focus on my window,
But there is a problem when i have focus on TextBox in that UserControl (Command is not fired).
Is that possible to catch that key pressure without lots of modifications in whole application?
A.
It sounds like your event is being handled before it bubbles up that far. Next I am wondering if you could move your input binding up to your window rather than a user control. My final option would be to remove your input bindings and create a global check in code.
Since you're already working with input bindings, I have added the code option below:
//In App.xaml.cs
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
EventManager.RegisterClassHandler(typeof(UIElement), UIElement.KeyDownEvent, new RoutedEventHandler(GlobalClick));
}
private void GlobalClick(object sender, RoutedEventArgs e)
{
var args = (KeyEventArgs) e;
if (args.KeyboardDevice.IsKeyDown(Key.M) &&
args.KeyboardDevice.IsKeyDown(Key.LeftCtrl) || args.KeyboardDevice.IsKeyDown(Key.RightCtrl))
MessageBox.Show("Works");
}
Documenting this answer for others, as there is a much simpler way to do this that is rarely referenced, and doesn't require touching the XAML at all.
To link a keyboard shortcut at the Window level, in the Window constructor simply add a new KeyBinding to the InputBindings collection. As the command, pass in your arbitrary command class that implements ICommand. For the execute method, simply implement whatever logic you need. In my example below, my WindowCommand class takes a delegate that it will execute whenever invoked. When I construct the new WindowCommand to pass in with my binding, I simply indicate in my initializer, the method that I want the WindowCommand to execute.
You can use this pattern to come up with your own quick keyboard shortcuts.
public YourWindow() //inside any WPF Window constructor
{
...
//add this one statement to bind a new keyboard command shortcut
InputBindings.Add(new KeyBinding( //add a new key-binding, and pass in your command object instance which contains the Execute method which WPF will execute
new WindowCommand(this)
{
ExecuteDelegate = TogglePause //REPLACE TogglePause with your method delegate
}, new KeyGesture(Key.P, ModifierKeys.Control)));
...
}
Create a simple WindowCommand class which takes an execution delegate to fire off any method set on it.
public class WindowCommand : ICommand
{
private MainWindow _window;
//Set this delegate when you initialize a new object. This is the method the command will execute. You can also change this delegate type if you need to.
public Action ExecuteDelegate { get; set; }
//You don't have to add a parameter that takes a constructor. I've just added one in case I need access to the window directly.
public WindowCommand(MainWindow window)
{
_window = window;
}
//always called before executing the command, mine just always returns true
public bool CanExecute(object parameter)
{
return true; //mine always returns true, yours can use a new CanExecute delegate, or add custom logic to this method instead.
}
public event EventHandler CanExecuteChanged; //i'm not using this, but it's required by the interface
//the important method that executes the actual command logic
public void Execute(object parameter)
{
if (ExecuteDelegate != null) //let's make sure the delegate was set
{
ExecuteDelegate();
}
else
{
throw new InvalidOperationException("ExecuteDelegate has not been set. There is no method to execute for this command.");
}
}
}
I'm sure this can be used for other controls as well, but haven't tried it.

Change WPF mainwindow label from another class and separate thread

Im working on a WPF application. I have a label called "Status_label" in MainWindow.xaml. and I want to change its content from a different class (signIn.cs).
Normally I'm able to do this
var mainWin = Application.Current.Windows.Cast<Window>().FirstOrDefault(window => window is MainWindow) as MainWindow;
mainWin.status_lable.Content = "Irantha signed in";
But my problem is,when I'm trying to access it via different thread in signIn.cs class, it gives an error:
The calling thread cannot access this object because a different thread owns it.
Can I solve this by using Dispatcher.Invoke(new Action(() =>{.......... or something else?
EDIT:
I'm gonna call this label change action from different class as-well-as separate thread
MainWindow.xaml
<Label HorizontalAlignment="Left" Margin="14,312,0,0" Name="status_lable" Width="361"/>
SignIn.cs
internal void getStudentAttendence()
{
Thread captureFingerPrints = new Thread(startCapturing);
captureFingerPrints.Start();
}
void mySeparateThreadMethod()
{
var mainWin = Application.Current.Windows.Cast<Window>().FirstOrDefault(window => window is MainWindow) as MainWindow;
mainWin.status_lable.Dispatcher.Invoke(new Action(()=> mainWin.status_lable.Content ="Irantha signed in"));
}
line var mainWin return errorThe calling thread cannot access this object because a different thread owns it.
Please guide me,
Thank you
I resolved my question, hope somebody will need this. But don't know whether this is the optimized way.
In my mainWindow.xaml.cs :
public MainWindow()
{
main = this;
}
internal static MainWindow main;
internal string Status
{
get { return status_lable.Content.ToString(); }
set { Dispatcher.Invoke(new Action(() => { status_lable.Content = value; })); }
}
from my SignIn.cs class
MainWindow.main.Status = "Irantha has signed in successfully";
This works fine for me.
You can find more details from here, Change WPF window label content from another class and separate thread
cheers!!
try below snippet:
status_lable.Dispatcher.Invoke(...)
Thanks to the answers, they led me in the right direction. I ended up with this simple solution:
public partial class MainWindow : Window
{
public static MainWindow main;
public MainWindow()
{
InitializeComponent();
main = this;
}
}
Then in my eventhandler in another class that runs in a different thred:
internal static void pipeServer_MessageReceived(object sender, MessageReceivedEventArgs e)
{
MainWindow.main.Dispatcher.Invoke(new Action(delegate()
{
MainWindow.main.WindowState = WindowState.Normal;
}));
}
This to show the minimized window when i message is received via a namedPipeline.
Thank you! I wound up with a slightly different solution, but you definitely pointed me in the right direction with your answer.
For my application, I have a lot of controls in main, and most of the method calls on main were occurring from within the scope of main, so it was simpler to use the default { get; set } within MainWindow.xaml.cs (or to just define the controls in XAML).
In my parent window's code-behind, I launch the MainWindow in a separate thread like this (simplified example). The key is to define main globally, even though it is instantiated inside of Window_Loaded():
public ParentWindow()
{
InitializeComponent();
}
MainWindow main;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Thread otherThread = new Thread(() =>
{
main = new MainWindow();
main.Show();
main.Closed += (sender2, e2) =>
main.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
});
otherThread.SetApartmentState(ApartmentState.STA);
otherThread.Start();
}
Then in my MainWindow code-behind, I just interact with the controls as though it is a simple single-threaded application (there is no control of the parent thread from the child thread in my case). I can, however, control main from the parent thread like this:
private void button_Click(object sender, RoutedEventArgs e)
{
main.Dispatcher.Invoke(new Action(delegate ()
{
main.myControl.myMethod();
}));
}
By doing it this way, I avoid the complexity of defining everything in code-behind and using the dispatcher from within the code-behind of MainWindow.xaml.cs. There are only a few spots in my application where I modify main from the parent window, so this was simpler for me, but your approach seems equally valid. Thanks again!
Simple trick without use Dispatcher.Invoke: In your Window class put this:
public partial class MyWindow: Window
{
public static MyWindow mywin;
[...]
public MyWindow()
{
InitializeComponent();
mywin = this;
[...]
}
[...]
}
Next in your second class to call the properties you need to add your window name + the label that you've assigned. This is an example:
internal class MySecondClass
{
internal void ChangeAValue()
{
MyWindow.mywin.ATextBox.Text = "Some text"; // I'm changing for example the text for a textbox in MyWindow.
}
}

WPF usercontrol showdialog problem

There is a MainWindow, a usercontrol which is located in my MainWindow and a OtherForm which I am going to show from usercontrol. I sent OtherForm as parameter from MainWindow to usercontrol. And in usercontrol I am calling OtherForm.showdialog. When I show it the second time, I am getting "Cannot set Visibility or call Show, ShowDialog, or WindowInteropHelper.EnsureHandle after a Window has closed" problem.
Code
In MainWindow class
void Example()
{
usercontrol.Load(new Otherform{ variable= 1 });
}
In Usercontrol class
private Window _form;
public void Load(window form)
{
_form=form;
}
void ExampleInUSerControl
{
_form.VerifyAccess();
_form.Activate();
_form.ShowActivated = true;
_form.ShowDialog();
}
The error message in this case is pretty accurate: once a Window is closed, it's closed for good. Since ShowDialog() always closes the window, you need to create a new instance of the window every time you call ShowDialog().
One fairly simple way to accomplish this in your example is to have the Load event take an argument of type Func<Window>:
In the MainWindow:
private Window MakeWindow()
{
return new MyWindow();
}
private void Example()
{
usercontrol.Load(MakeWindow);
}
In the user control:
public void Load(Func<T> makeWindow)
{
_form = makeWindow();
...
}
Note, by the way, that there should be no reason to call Activate or set ShowActivated - ShowDialog will do all that. And I don't know why you'd call VerifyAccess either.

Resources