C#: Change WindowState of main window from a different class - c#

I have one the most default class of my window and second class I call from it. I need to change the WindowState of a MainWindow window from that second class but when I try to do it by: MainWindow.WindowState = WindowState.Normal; it gives me this error: An object reference is required for the non-static field, method, of property 'Window.WindowState'.
MainWindow.xaml.cs:
namespace Client_Patcher
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
UnminimizeApplicationCommand.cs:
namespace Client_Patcher
{
public class UnminimizeApplicationCommand : ICommand
{
public UnminimizeApplicationCommand(WindowState d)
{
}
public bool CanExecute(object parameter)
{
throw new NotImplementedException();
}
public void Execute(object parameter)
{
//Need to change WindowState property of a MainWindow here.
}
public event EventHandler CanExecuteChanged;
event EventHandler ICommand.CanExecuteChanged
{
add
{
throw new NotImplementedException();
}
remove
{
throw new NotImplementedException();
}
}
}
}
Also, I tried to do this:
namespace Client_Patcher
{
public partial class MainWindow : Window
{
public MainWindow AppWindow { get; }
public MainWindow()
{
InitializeComponent();
AppWindow = this;
}
}
}
Which is called by MainWindow.AppWindow.WindowState = WindowState.Normal; way, but gives the same error. What is the work aroud?

This error occurs because you are treating MainWindow like a static object. But in fact it isn't. With this in mind and now when reading the error message again, you will realize that it informs you exactly about this issue. To solve this try
Application.Current.MainWindow.WindowState = WindowState.Normal;
inside your Execute callback

I recommend using something called an "IoC container"
Create a static class.
public static IoC
{
private static Window _window;
// The main window instance for your app
public static Window Window => _window;
// Here you pass your application's "main" window instance.
// So all window related intractability happens only from this clas
public static InitializeDI(Window window)
{
_window = window;
}
}
Note:
You should really call this method in the Main() method where your application starts

Related

Cannot share a view into mutiple component

I got a task that need to share camera view from a webcam into 2 Window. I've tried using singleton for create camera view only one time. The problem is that created instance can not share between 2 class. I'm now really confused. What am I doing wrong here?
MainWindow class
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ReceptionMainWindow receptionMainWindow = new ReceptionMainWindow();
CustomerMainWindow customerMainWindow = new CustomerMainWindow();
receptionMainWindow.Show();
customerMainWindow.Show();
this.Hide();
}
}
Receptionist class
public partial class ReceptionMainWindow : Window
{
public ReceptionMainWindow()
{
InitializeComponent();
ReceptionWindowHoler.Content = CameraPage.getInstance();
}
}
Customer Class
public partial class CustomerMainWindow : Window
{
public CustomerMainWindow()
{
InitializeComponent();
CustomerWindowHoler.Content = CameraPage.getInstance();
}
}
private static CameraPage instance;
Camera class
public CameraPage()
{
InitializeComponent();
//DataContext = CameraViewModel.getInstance();
this.DataContext = this;
GetVideoDevices();
}
public static CameraPage getInstance()
{
if (instance == null)
instance = new CameraPage();
return instance;
}
You could create a Bitmap from the camera view and share it via events to the two other windows.
Take this answer as a workaround. There must be a better way.

WPF- How can i use a List that i declare and fill in my MainWindow in a Usercontrol?

Hi i need to be able to use a list from my Main Window in a Usercontrol i need to be able to edit and read from it in various Usercontrols.
MainWindow:
public partial class MainWindow : Window
{
public List<Termin> termine = new List<Termin>();
public MainWindow()
{
InitializeComponent();
}
}
Usercontrol:
public partial class KalenderAnsicht : UserControl
{
public KalenderAnsicht()
{
InitializeComponent();
}
private void SomeMethod()
{
//i need to be able to use the list here
}
}
You need to get a reference to the MainWindow one way or another. The easiest way to do this is probably to use the Application.Current.Windows property:
private void SomeMethod()
{
var mw = Application.Current.Windows.OfType<MainWindow>().FirstOrDefault();
List<Termin> termine = mw.termine;
//...
}
You could also consider making termine static:
public partial class MainWindow : Window
{
public static List<Termin> termine = new List<Termin>();
public MainWindow()
{
InitializeComponent();
}
}
...and access it directly without a reference to an instance of MainWindow:
private void SomeMethod()
{
List<Termin> termine = MainWindow.termine;
//...
}

How to add a Canvas event from another class? WPF C#

I have a MainWindow class, and that is the main window of the app. I've created another class just below the MainWindow class, and I need to add an event to a Canvas that was created in MainWindow. The method I want to add as event is also in MainWindow.
public partial class MainWindow : Window
{
public void Moving(object sender, MouseEventArgs e)
{
bla bla;
}
public Canvas Getcanvas
{
get
{
return canvas;
}
}
}
public class Ka
{
public Ka()
{
MainWindow.Getcanvas.MouseMove += new MouseEventHandler(//HERE!!! I DONT KNOW WHAT GOES HERE, here should probably be MainWindow.Moving but I get error "An object reference.."
}
}
Please help me !
var mainWindowInstant = (MainWindow)App.Current.MainWindow;
mainWindowInstant.Getcanvas.MouseMove += new MouseEventHandler(...);

Implementing "close window" command with MVVM

So my first attempt did everything out of the code behind, and now I'm trying to refactor my code to use the MVVM pattern, following the guidance of the MVVM in the box information.
I've created a viewmodel class to match my view class, and I'm moving the code out of the code behind into the viewmodel starting with the commands.
My first snag is trying to implement a 'Close' button that closes the window if the data has not been modified. I've rigged up a CloseCommand to replace the 'onClick' method and all is good except for where the code tries to run this.Close(). Obviously, since the code has been moved from a window to a normal class, 'this' isn't a window and therefore isn't closeable. However, according to MVVM, the viewmodel doesn't know about the view, so i can't call view.Close().
Can someone suggest how I can close the window from the viewmodel command?
I personally use a very simple approach: for every ViewModel that is related to a closeable View, I created a base ViewModel like this following example:
public abstract class CloseableViewModel
{
public event EventHandler ClosingRequest;
protected void OnClosingRequest()
{
if (this.ClosingRequest != null)
{
this.ClosingRequest(this, EventArgs.Empty);
}
}
}
Then in your ViewModel that inherits from CloseableViewModel, simply call this.OnClosingRequest(); for the Close command.
In the view:
public class YourView
{
...
var vm = new ClosableViewModel();
this.Datacontext = vm;
vm.ClosingRequest += (sender, e) => this.Close();
}
You don't need to pass the View instance to your ViewModel layer. You can access the main window like this -
Application.Current.MainWindow.Close()
I see no issue in accessing your main window in ViewModel class as stated above. As per MVVM principle there should not be tight coupling between your View and ViewModel i.e. they should work be oblivious of others operation. Here, we are not passing anything to ViewModel from View. If you want to look for other options this might help you - Close window using MVVM
My solution to close a window from view model while clicking a button is as follows:
In view model
public RelayCommand CloseWindow;
Constructor()
{
CloseWindow = new RelayCommand(CloseWin);
}
public void CloseWin(object obj)
{
Window win = obj as Window;
win.Close();
}
In View, set as follows
<Button Command="{Binding CloseWindowCommand}" CommandParameter="{Binding ElementName=WindowNameTobeClose}" Content="Cancel" />
I do it by creating a attached property called DialogResult:
public static class DialogCloser
{
public static readonly DependencyProperty DialogResultProperty =
DependencyProperty.RegisterAttached(
"DialogResult",
typeof(bool?),
typeof(DialogCloser),
new PropertyMetadata(DialogResultChanged));
private static void DialogResultChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var window = d as Window;
if (window != null && (bool?)e.NewValue == true)
window.Close();
}
public static void SetDialogResult(Window target, bool? value)
{
target.SetValue(DialogResultProperty, value);
}
}
then write this to you XAML, in the window tag
WindowActions:DialogCloser.DialogResult="{Binding Close}"
finally in the ViewModel
private bool _close;
public bool Close
{
get { return _close; }
set
{
if (_close == value)
return;
_close = value;
NotifyPropertyChanged("Close");
}
}
if you change the Close to true, the window will be closed
Close = True;
Here is the simplest and pure MVVM solution
ViewModel Code
public class ViewModel
{
public Action CloseAction { get; set; }
private void CloseCommandFunction()
{
CloseAction();
}
}
Here is XAML View Code
public partial class DialogWindow : Window
{
public DialogWindow()
{
ViewModel vm = new ViewModel();
this.DataContext = vm;
vm.CloseAction = Close;
}
}
This solution is quick and easy. Downside is that there is some coupling between the layers.
In your viewmodel:
public class MyWindowViewModel: ViewModelBase
{
public Command.StandardCommand CloseCommand
{
get
{
return new Command.StandardCommand(Close);
}
}
public void Close()
{
foreach (System.Windows.Window window in System.Windows.Application.Current.Windows)
{
if (window.DataContext == this)
{
window.Close();
}
}
}
}
MVVM-light with a custom message notification to avoid the window to process every notificationmessage
In the viewmodel:
public class CloseDialogMessage : NotificationMessage
{
public CloseDialogMessage(object sender) : base(sender, "") { }
}
private void OnClose()
{
Messenger.Default.Send(new CloseDialogMessage(this));
}
Register the message in the window constructor:
Messenger.Default.Register<CloseDialogMessage>(this, nm =>
{
Close();
});
This is very similar to eoldre's answer. It's functionally the same in that it looks through the same Windows collection for a window that has the view model as its datacontext; but I've used a RelayCommand and some LINQ to achieve the same result.
public RelayCommand CloseCommand
{
get
{
return new RelayCommand(() => Application.Current.Windows
.Cast<Window>()
.Single(w => w.DataContext == this)
.Close());
}
}
using MVVM-light toolkit:
In the ViewModel:
public void notifyWindowToClose()
{
Messenger.Default.Send<NotificationMessage>(
new NotificationMessage(this, "CloseWindowsBoundToMe")
);
}
And in the View:
Messenger.Default.Register<NotificationMessage>(this, (nm) =>
{
if (nm.Notification == "CloseWindowsBoundToMe")
{
if (nm.Sender == this.DataContext)
this.Close();
}
});
This is taken from ken2k answer (thanks!), just adding the CloseCommand also to the base CloseableViewModel.
public class CloseableViewModel
{
public CloseableViewModel()
{
CloseCommand = new RelayCommand(this.OnClosingRequest);
}
public event EventHandler ClosingRequest;
protected void OnClosingRequest()
{
if (this.ClosingRequest != null)
{
this.ClosingRequest(this, EventArgs.Empty);
}
}
public RelayCommand CloseCommand
{
get;
private set;
}
}
Your view model, inherits it
public class MyViewModel : CloseableViewModel
Then on you view
public MyView()
{
var viewModel = new StudyDataStructureViewModel(studyId);
this.DataContext = viewModel;
//InitializeComponent(); ...
viewModel.ClosingRequest += (sender, e) => this.Close();
}
Given a way, Please check
https://stackoverflow.com/a/30546407/3659387
Short Description
Derive your ViewModel from INotifyPropertyChanged
Create a observable property CloseDialog in ViewModel, Change CloseDialog property whenever you want to close the dialog.
Attach a Handler in View for this property change
Now you are almost done. In the event handler make DialogResult = true
first of all give your window a name like
x:Name="AboutViewWindow"
on my close button I've defined Command and Command Parameter like
CommandParameter="{Binding ElementName=AboutViewWindow}"
Command="{Binding CancelCommand}"
then in my view model
private ICommand _cancelCommand;
public ICommand CancelCommand
{
get
{
if (_cancelCommand == null)
{
_cancelCommand = new DelegateCommand<Window>(
x =>
{
x?.Close();
});
}
return _cancelCommand;
}
}
Most MVVM-compliant solution using HanumanInstitute.MvvmDialogs
Implement ICloseable interface in your ViewModel and that's it!
No code in your view whatsoever.

In WPF, how can a Command's CanExecute method gain visibility of other UI elements?

I've been using WPF for a while but I'm new to Commands, but would like to start using them properly for once. Following a code example, I've established a separate static Commands class to hold all of my commands, and it looks like this.
public static class Commands
{
public static RoutedUICommand OpenDocument { get; set; }
static Commands()
{
OpenDocument = new RoutedUICommand("Open Document", "OpenDocument", typeof(Commands));
}
public static void BindCommands(Window window)
{
window.CommandBindings.Add(new CommandBinding(OpenDocument, OpenDocument_Executed, OpenDocument_CanExecute));
}
private static void OpenDocument_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
// Should be set to true if an item is selected in the datagrid.
}
private static void OpenDocument_Executed(object sender, ExecutedRoutedEventArgs e)
{
}
}
My problem is that although the command is going to be bound to a Button control in MainWindow.xaml, the OpenDocument_CanExecute method needs to look at a DataGrid in MainWindow.xaml to see if an item is selected.
How can I wire things up such that the method can see the DataGrid?
SOLUTION
Inspired by Ken's reply (thanks again!), I put the following in place, which works perfectly.
MainWindow.xaml.cs
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
Loaded += delegate
{
DataContext = ViewModel.Current;
Commands.BindCommands(this);
};
}
}
ViewModel.cs
public class ViewModel
{
private static ViewModel _current;
public static ViewModel Current
{
get { return _current ?? (_current = new ViewModel()); }
set { _current = value; }
}
public object SelectedItem { get; set; }
}
Commands.cs
public static class Commands
{
public static RoutedUICommand OpenDocument { get; set; }
static Commands()
{
OpenDocument = new RoutedUICommand("Open Document", "OpenDocument", typeof(Commands));
}
public static void BindCommands(Window window)
{
window.CommandBindings.Add(new CommandBinding(OpenDocument, OpenDocument_Executed, OpenDocument_CanExecute));
}
private static void OpenDocument_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = ViewModel.Current.SelectedItem != null;
}
private static void OpenDocument_Executed(object sender, ExecutedRoutedEventArgs e)
{
}
}
ICommand implementations work best in the MVVM pattern:
class ViewModel : INotifyPropertyChanged {
class OpenDocumentCommand : ICommand {
public bool CanExecute(object parameter) {
return ViewModel.ItemIsSelected;
}
public OpenDocumentCommand(ViewModel viewModel) {
viewModel.PropertyChanged += (s, e) => {
if ("ItemIsSelected" == e.PropertyName) {
RaiseCanExecuteChanged();
}
};
}
}
private bool _ItemIsSelected;
public bool ItemIsSelected {
get { return _ItemIsSelected; }
set {
if (value == _ItemIsSelected) return;
_ItemIsSelected = value;
RaisePropertyChanged("ItemIsSelected");
}
}
public ICommand OpenDocument {
get { return new OpenDocumentCommand(this); }
}
}
Obviously, I left out a whole bunch of stuff. But this pattern has worked well for me in the past.
why even implement a command if you are tightly coupling it to UI implementation? Just respond to datagrid.SelectionChanged and code in what supposed to happen.
Otherwise, put it in the ViewModel. Have the ViewModel monitor it's state and evaluate when CanExe is true.
Edit
On the other hand, you can pass a parameter to your command, as well as Exe() & CanExe() methods
//where T is the type you want to operate on
public static RoutedUICommand<T> OpenDocument { get; set; }
If you are doing an MVVM solution, this would be the perfect time to implement a publish / subscribe aggregator that allows controls to "talk" to each other. The gist behind it is that the datagrid would publish an event, 'Open Document'. Subsequent controls could subscribe to the event and react to the call to 'Open Document'. The publish / subscribe pattern prevents tightly coupling the datagrid and the control. Do some searches for event aggregators and I think you'll be on your way.

Categories

Resources