Ok so I'm just making a mock MVC app to get a handle on how things work
my model has some string in it (and more, but don't care at the moment)
my GUI has a bunch of radiobuttons and here is what I do
private class radioButtonEvent : Model.EventHandling.XObjectEvent{
private List<RadioButton> myList;
public radioButtonEvent() { }
public override void execute(){
foreach (RadioButton a in myList){
if (a.Text == ((Model.InfoTree)myObj).Info){
a.Checked = true;
((TabControl)a.Parent.Parent).SelectTab(a.Parent.Name);
}
}
}
public void setRadioList(List<RadioButton> a){
myList = a;
}
}
I create one of these and add a list of all my radiobuttons then make it listen to a certain string, like so:
radioButtonEvent locationEvent = new radioButtonEvent();
List<RadioButton> radioList = new List<RadioButton>();
radioList.Add(Location_Logged_Arena_radioButton);
radioList.Add(Location_Logged_Market_radioButton);
radioList.Add(Location_Logged_Mute_radioButton);
radioList.Add(Location_Logged_Town_radioButton);
radioList.Add(Location_Logged_Vault_radioButton);
radioList.Add(Location_Logging_Home_radioButton);
radioList.Add(Location_Logging_Select_radioButton);
locationEvent.setRadioList(radioList);
myModel.InformationTree.addInfoEvent(locationEvent);
one thing I should point out is that in XObjectEvent there is a method that gets inherited that handles the setting of myobj
now the two ways I've currently thought of going about having listenable strings are these:
Way 1:
private ListenableString lstring = new ListenableString();
public string Info{
get
{ return lstring.Text;}
set
{ lstring.Text = value;}
}
public void addInfoEvent(XEvent ev){
lstring.addEvent(ev);
}
and this uses the following
class ListenableString
{
public ListenableString() { }
private string me = "";
private List<XEvent> Events = new List<XEvent>();
public void addEvent(XEvent ev){
Events.Add(ev);
}
public string Text{
get
{ return me;}
set{
me = value;
foreach (EventHandling.XObjectEvent x in Events){
x.setObject(this);
x.execute();
}
}
}
}
Way 2:
private List<XEvent> infoEvents = new List<XEvent>();
public void addInfoEvent(XEvent ev)
{
infoEvents.Add(ev);
}
private string _Info = "";
public string Info
{
get
{
return _Info;
}
set
{
_Info = value;
foreach (EventHandling.XObjectEvent x in infoEvents)
{
x.setObject(this);
x.execute();
}
}
}
Way 3
got a better way? :)
Ye Olde New Answer
Here are some Stack Overflow questions that deal with implementing MVC in a Windows Form Application:
Implementing MVC with Windows Forms.
How would you implement MVC in a Windows Form Application?
Ye Olde Olde Answer
Use ASP.NET MVC 1.0.
Related
I created WPF on the MVVM principle, but I can't make it possible to open another one from the current page.
I followed this example
We need something like this:
Example
It is also worth considering that a page instance should be created. (That is, so that you can open yourself from Page 2, but with a different name)
My failed attempt:
Page 2 ViewModel
public Page2ViewModel()
{
ButtonCommand = new RelayCommand(o => LoadOtherView());
}
public string Title { get; set; } = "Page2";
public string Text { get; set; } = "Page two";
public ICommand ButtonCommand { get; set; }
private void MainButtonClick(object sender)
{
//MainViewModel main = new MainViewModel();
//main.SelectedPageViewModel = main.PageViewModels[0];
//main.SelectedPageViewModel.Title = "да";
//main.SelectedPageViewModel.Text = "Первая страница";
}
private void LoadOtherView()
{
// Instead of interacting with a whole ViewModel, we just use the interface
//_pageDisplay.ChangePageCommand.Execute(new ContactViewModel());
_pageDisplay.ChangeViewModel(_listPageViewModels[0]);
}
Interfaces
namespace WpfMVVMCore.Interfaces
{
public interface IPageDisplay
{
public IPageViewModel GetCurrentPage();
public IList<IPageViewModel> ListPageViewModels();
public void ChangeViewModel(IPageViewModel newPage);
}
}
MainViewModel
public MainViewModel(IPageDisplay pageDisplay, IList<IPageViewModel> ListPageViewModels)
{
_pageDisplay = pageDisplay;
_pageViewModels = ListPageViewModels;
}
public IPageViewModel GetCurrentPage()
{
return _selectedPageViewModel;
}
public void ChangeViewModel(IPageViewModel newPage)
{
this.SelectedPageViewModel = newPage;
}
public IList<IPageViewModel> ListPageViewModels()
{
return _pageViewModels;
}
** If the information provided by me is not enough for you, you can download this project (with my unsuccessful attempt 🤭 ):download**
P.S. Please do not criticize me if it is not difficult for you. I'm new to MVVM. Better help :)
I have an Item class in C# and I want to have two methods, OnRightClick and OnLeftClick, but I want every item to do different things upon using them (I am on Unity and this class is not a monoBehavior).
I heard about virtual methods, but from what I realized they can be overridden only from other classes that inherit them. However, I want to do without making a separate class for every item I make. How can I make those 2 methods vary?
I thought of using delegate, but it doesn't work the way I expected it to either. Is it even possible?
EDIT
(Ik the following line are not a thing but this is the best way I can somehow explain what I want to do)
Imagine having the following simple class Item
public class Item
{
private string name;
private float weight;
private int price;
private bool dropable;
public Item(string name, float weight, int price, bool dropable)
{
this.name = name;
this.weight = weight;
this.price = price;
this.dropable = dropable;
}
public Item(string name, float weight, int price)
{
this.name = name;
this.weight = weight;
this.price = price;
this.dropable = true;
}
public string GetName()
{
return this.name;
}
public float GetWeight()
{
return this.weight;
}
public int GetPrice()
{
return this.price;
}
public bool GetDropable()
{
return this.dropable;
}
public void SetDropable(bool dropable)
{
this.dropable = dropable;
}
}
I want to be able to make an OnRightClick and OnLeftClick that would vary from every item I create if I could do something like(As I said I know it's not valid but this is the best way I can explain it, also didn't mention it in the class above, this is the original class I currently have)
Item item1 = new Item(*all the stuff here*);
Item item2 = new Item(*other stuff*);
item1.OnRightClick = delegate {*what I want on right click*};
item1.OnRightClick(); //executes the function for item1
item2.OnRightClick = delegate {*other stuff on right click*};
item2.OnRightClick(); //executes a different function for item2
Again, this is not a valid code but I just used this to try and explain what I want to try and do, and to ask if there is any solutions to this that exist. In the worst case, if there aren't, I could just use virtual but I'd like that to be my last case of no choice.
You can have a parent Item class then different children item classes that inherit from it the syntax it
public class MyItem : MonoBehaviour {
public enum ItemType {HEALING, OFFENSIVE, CONSUMABLE, EQUIPMENT}
public ItemType itemType;
public float potency;
public MyItem(ItemType _it, float _potency) {
itemType = _it;
potency = _potency;
}
public void OnRightClick() {
switch (itemType) {
case ItemType.HEALING:
HealCharacter(character, potency);
break;
case ItemType.OFFENSIVE:
break;
// more cases
}
}
public void OnLeftClick() {
//fill in like onrightclick
}
}
You can use Action and Func to do what you are asking.
https://learn.microsoft.com/en-us/dotnet/api/system.action-1?view=netcore-3.1
https://learn.microsoft.com/en-us/dotnet/api/system.func-2?view=netcore-3.1
public enum ItemType
{
Sword,
Shield,
Potion
}
public class Item
{
private readonly Action leftClickHandler;
private readonly Action<int> leftClickHandlerWithParam;
private readonly Action rightClickHandler;
private readonly Action<int> rightClickHandlerWithParam;
public Item(ItemType itemType)
{
switch (itemType)
{
case ItemType.Potion:
this.rightClickHandler = this.HandleClickWithFlash;
this.leftClickHandler = this.HandleClickWithSound;
this.leftClickHandlerWithParam = this.HandleClickWithFlash;
this.rightClickHandlerWithParam = this.HandleClickWithSound;
break;
}
}
public void HandleLeftClick()
{
this.leftClickHandler();
}
public void HandleRightClick()
{
this.rightClickHandler();
}
private void HandleClickWithFlash()
{
// Logic here.
}
private void HandleClickWithFlash(int parameter)
{
// Logic here.
}
private void HandleClickWithSound()
{
// Logic here.
}
private void HandleClickWithSound(int parameter)
{
// Logic here.
}
}
Here it is with the items exposed, if say you wanted a item factory concept.
public class ItemSettableHandlers
{
public ItemSettableHandlers()
{
}
public Action LeftClickHandler { get; set; }
public Action RightClickHandler { get; set; }
public void HandleLeftClick()
{
this.LeftClickHandler?.Invoke();
}
public void HandleRightClick()
{
this.RightClickHandler?.Invoke();
}
}
public class ItemCreator
{
public void CreateItems()
{
var itemSword = new ItemSettableHandlers();
itemSword.LeftClickHandler = () =>
{
// Do sword left click here.
};
itemSword.RightClickHandler = () =>
{
// Do sword right click here.
};
var itemShield = new ItemSettableHandlers();
itemShield.LeftClickHandler = () =>
{
// Do shield left click here.
};
itemShield.RightClickHandler = () =>
{
// Do shield right click here.
};
}
}
You could use EventHandler:
in you class, you define:
public event EventHandler RightClick;
public void OnRightClick()
{
EventHandler handler = RightClick;
if (null != handler) handler(this, EventArgs.Empty);
}
You use like that:
// Enable Event
RightClick += new EventHandler(OnRightClick);
OnRightClick();
public void OnRightClick(object s, EventArgs e)
{
}
I'm making user changeable settings for my media player and I'm struggling to find an elegant solution to the problem.
One of my settings for example - pauses the video at it's last frame, if not checked it will either continue through the playlist or if it's only 1 file, reset it and pause it at the start.
This is how I've implemented it:
private void OnMediaEndedCommand()
{
if (GeneralSettings.PauseOnLastFrame)
{
MediaPlayer.SetMediaState(MediaPlayerStates.Pause);
return;
}
if (PlayListViewModel.FilesCollection.Last().Equals(PlayListViewModel.FilesCollection.Current) && !Repeat)
{
ChangeMediaPlayerSource(PlayListViewModel.ChangeCurrent(() => PlayListViewModel.FilesCollection.MoveNext()));
MediaPlayer.SetMediaState(MediaPlayerStates.Stop);
return;
}
ChangeMediaPlayerSource(PlayListViewModel.ChangeCurrent(() => PlayListViewModel.FilesCollection.MoveNext()));
}
This is contained inside the ViewModel of the main window, where the media element is and GeneralSettings.PauseOnLastFrame is a boolean property.
This command is binded as follows:
<MediaElement ....>
<ia:Interaction.Triggers>
<ia:EventTrigger EventName="MediaEnded">
<ia:InvokeCommandAction Command="{Binding MediaEndedCommand}"/>
</ia:EventTrigger>
</ia:Interaction.Triggers>
</MediaElement>
It works but it's awful, how should I go about implementing such setting system in an elegant way? Some settings might not be boolean, they might have multiple options, some might be applied only on startup and others, as the one illustrated above, event based.
Based on the information and sample code you provided, I would suggest
Approach - 1
A tightly couple ViewModel with System.Configuration.ApplicationSettingsBase and you can mention all you properties in ViewModel and map single of them with a separate application setting property. You can use your settings directly in biding afterwards e.g. : {x:Static Settings.Default.Whatevs}. Othe "Save" button click event or main window close event, you can save all you settings e.g. : Settings.Default.Save();
Approach - 2
A better approach, I would suggest / prefer (if I am developing this app) is to develop a wrapper class (e.g.: SettingProvider) that implement an inheritance (e.g: ISettingProvider) which uncovers all you settings as separate properties and also have a save method which saves all setting values. You can use this wrapper class into your ViewModel to handle all the commands and setting values in better way.
The benefit of this approach is the if you decide to change you setting to database , you need not to make change to you ViewModel as all job is done in SettingProvider class.
I am not sure but based on viewing your code, I assume that you used Approach-1. Please put you comments and any feedback to this answer. I would like to know what you think and may be you have got more simple and interesting way of achieving this.
UPDATE-1
Example
Enum for showing you demo
public enum MediaStatus
{
Playing = 0,
Stopped = 1,
Paused = 2
}
Interface
public interface ISettingProvider
{
double Volumne { get; set; }
string LastMediaUrl { get; set; }
MediaStatus PlayingMediaStatus;
void SaveSettings();
}
Wrapper Class
public class SettingProvider : ISettingProvider
{
private double volumne;
public double Volumne // read-write instance property
{
get
{
return volumne;
}
set
{
volumne = value;
Settings.Default.Volumne = volumne;
}
}
private string lastMediaUrl;
public string LastMediaUrl // read-write instance property
{
get
{
return lastMediaUrl;
}
set
{
lastMediaUrl = value;
Settings.Default.LastMediaUrl = lastMediaUrl;
}
}
private MediaStatus playingMediaStatus;
public MediaStatus PlayingMediaStatus // read-write instance property
{
get
{
return playingMediaStatus;
}
set
{
playingMediaStatus = value;
Settings.Default.PlayingMediaStatus = (int)playingMediaStatus;
}
}
public void SaveSettings()
{
Settings.Default.Save();
}
//Constructor
public SettingProvider()
{
this.Volumne = Settings.Default.Volumne;
this.LastMediaUrl = Settings.Default.LastMediaUrl;
this.PlayingMediaStatus = (MediaStatus)Settings.Default.PlayingMediaStatus;
}
}
ViewModelBase Class
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
CommandHandler Class
public class CommandHandler : ICommand
{
public event EventHandler CanExecuteChanged { add { } remove { } }
private Action<object> action;
private bool canExecute;
public CommandHandler(Action<object> action, bool canExecute)
{
this.action = action;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute;
}
public void Execute(object parameter)
{
action(parameter);
}
}
ViewModel
public class SettingsViewModel : ViewModelBase
{
SettingProvider objSettingProvider = new SettingProvider();
public double Volumne
{
get
{
return objSettingProvider.Volumne;
}
set
{
objSettingProvider.Volumne = value;
OnPropertyChanged("Volumne");
}
}
// Implementaion of other properties of SettingProvider with your ViewModel properties;
private ICommand saveSettingButtonCommand;
public ICommand SaveSettingButtonCommand
{
get
{
return saveSettingButtonCommand ?? (saveSettingButtonCommand = new CommandHandler(param => saveSettings(param), true));
}
}
private void saveSettings()
{
objSettingProvider.SaveSettings();
}
}
UPDATE-2
public interface ISettingProvider
{
bool PauseOnLastFrame;
bool IsAutoPlay;
MediaStatus PlayingMediaStatus;
void SaveSettings();
}
public class SettingProvider : ISettingProvider
{
private bool pauseOnLastFrame;
public bool PauseOnLastFrame // read-write instance property
{
get
{
return pauseOnLastFrame;
}
set
{
pauseOnLastFrame = value;
Settings.Default.PauseOnLastFrame = volumne;
}
}
private bool isAutoPlay;
public bool IsAutoPlay // read-write instance property
{
get
{
return isAutoPlay;
}
set
{
isAutoPlay = value;
Settings.Default.IsAutoPlay = volumne;
}
}
}
public class SettingsViewModel : ViewModelBase
{
SettingProvider objSettingProvider = new SettingProvider();
MediaStatus PlayingMediaStatus
{
get
{
return objSettingProvider.PlayingMediaStatus;
}
set
{
if(value == MediaStatus.Paused)
MediaPlayer.Pause();
if(value == MediaStatus.Playing)
MediaPlayer.Play();
if(value == MediaStatus.Stopped)
MediaPlayer.Stop();
objSettingProvider.PlayingMediaStatus = (int)value;
OnPropertyChanged("PlayingMediaStatus");
}
}
private string currentMediaFile;
public string CurrentMediaFile
{
get
{
return currentMediaFile;
}
set
{
currentMediaFile = value;
MediaPlayer.Stop();
MediaPlayer.Current = currentMediaFile;
if(objSettingProvider.IsAutoPlay)
MediaPlayer.Play();
OnPropertyChanged("CurrentMediaFile");
}
}
// Implementaion of other properties of SettingProvider with your ViewModel properties;
private ICommand onMediaEndedCommand;
public ICommand OnMediaEndedCommand
{
get
{
return onMediaEndedCommand ?? (onMediaEndedCommand = new CommandHandler(param => onMediaEnded(param), true));
}
}
private void onMediaEnded()
{
if(objSettingProvider.PauseOnLastFrame)
{
PlayingMediaStatus = MediaStatus.Paused;
}
else if(PlayListViewModel.FilesCollection.Last().Equals(PlayListViewModel.FilesCollection.Current) && !Repeat)
{
PlayingMediaStatus = MediaStatus.Stopped;
}
else
{
CurrentMediaFile = PlayListViewModel.FilesCollection.MoveNext();
}
}
}
NOTE: This is the detailed example I put here and also avoid some syntax error or naming error if I missed somewhere. Please correct it.
I am not aware which media player settings you are using. I took some sample properties. This is just an example of structure you can implement for you application. You may need to alter more code to implement this structure.
An elegant way to implement this IMHO would be to use a dependency injection container, this will provide great flexibility while allowing you to completely separate concerns (i.e. the settings implementation from your view models and custom controls).
There are many DI frameworks out there, for my example I will use simple injector because it is free (open source), simple and fast but you can apply the same principle to other frameworks (Unity, Ninject, etc..).
Start by creating an interface for your settings service, for example:
public interface ISettingsService
{
double Volumne { get; set; }
string LastMediaUrl { get; set; }
MediaStatus PlayingMediaStatus;
void SaveSettings();
}
Then add your implementation for the service, the beauty of using DI is that you can change the implementation at anytime or completely replace it and your application will continue to work as usual.
Let's say you want to use application settings, here is your service:
public class SettingsServiceFromApplication : ISettingsService
{
public double Volume
{
get
{
return Properties.Settings.Volume;
}
}
[...]
}
Or let's say you want to use a database to store your settings:
public class SettingsServiceFromDb : ISettingsService
{
public double Volume
{
get
{
return MyDb.Volumen;
}
}
[...]
}
Then you can use a DI container to specify which implementation to use:
Start by installing the library using NuGet:
Install-Package SimpleInjector -Version 4.0.12
You need a way to share your container throughout the application, I usually just go with a static class that I initialize when starting the app:
using Container = SimpleInjector.Container;
namespace YourNamespace
{
public class Bootstrapper
{
internal static Container Container;
public static void Setup()
{
//Create container and register services
Container = new Container();
//Let's specify that we want to use SettingsServiceFromApplication
Container.Register<ISettingsService, SettingsServiceFromApplication>();
//You can use your bootstrapper class to initialize other stuff
}
}
You need to call Setup when starting the App, the best place is in the App constructor:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Bootstrapper.Setup();
}
}
So now you have an app wide depedency injection container that you can use to request "services" (specific implementations of an interface).
To get the settings implementation in your view models you could simply call the container as follows:
// This will return an instance of SettingsServiceFromApplication
ISettingsService settingsService = Bootstrapper.Container.GetInstance<ISettingsService>();
double volumen = settingsService.Volume;
To make it easier to work with, I usually create a base view model that will allow to get services more easyly, for example:
public abstract BaseViewModel
{
private ISettingsService _settings;
protected ISettingsService GeneralSettings
{
get
{
if (_settings == null)
_settings = Bootstrapper.Container.GetInstance<ISettingsService>();
return _settings;
}
}
}
Every view model inheriting from this class will have access to the settings:
public class YourViewModel : BaseViewModel
{
private void OnMediaEndedCommand()
{
if (GeneralSettings.PauseOnLastFrame)
{
MediaPlayer.SetMediaState(MediaPlayerStates.Pause);
return;
}
if (PlayListViewModel.FilesCollection.Last().Equals(PlayListViewModel.FilesCollection.Current) && !Repeat)
{
ChangeMediaPlayerSource(PlayListViewModel.ChangeCurrent(() => PlayListViewModel.FilesCollection.MoveNext()));
MediaPlayer.SetMediaState(MediaPlayerStates.Stop);
return;
}
ChangeMediaPlayerSource(PlayListViewModel.ChangeCurrent(() => PlayListViewModel.FilesCollection.MoveNext()));
}
}
As you can see the code is the same as your code! But now the settings are coming from your container. Where is the elegance? Well, let's say that one year from now someone decides that you will store your settings in a database, what do you need to change in your code?
Container.Register<ISettingsService, SettingsServiceFromDb>();
A single line. Everything else should work as usual.
As well as view models, you could use this mechanism in your own controls:
public class MyMediaElement : UserControl //Or MediaElement and instead of commands you can override real events in the control code behind, this does not break the MVVM pattern at all, just make sure you use depedency properties if you need to exchange data with your view models
{
private void OnMediaEndedCommand()
{
//Get your settings from your container, do whatever you want to do depending on the settings
[...]
}
}
Then just use your control in your Views / ViewModels:
<local:MyMediaElement />
Yep, that's all you need because you handle everything in your User / Custom control, your view models doesn't need to care about how you handle settings in the control.
There are many options you can use to register containers, I recommend you take a look at the docs:
https://simpleinjector.org/index.html
https://simpleinjector.readthedocs.io/en/latest/index.html
I think maybe you are looking for an interface approach?
public interface IMediaEndedHandler
{
bool AlternateHandling(MediaPlayer player);
}
public class NullMediaEndedHandler : IMediaEndedHandler
{
public bool AlternateHandling(MediaPlayer player)
{
return false;
}
}
public class PauseOnLastFrameHandler : IMediaEndedHandler
{
public bool AlternateHandling(MediaPlayer player)
{
player.SetMediaState(MediaPlayerStates.Pause);
return true;
}
}
public class GeneralSettings
{
private bool pauseOnLastFrame;
private bool PauseOnLastFrame
{
get
{
return pauseOnLastFrame;
}
set
{
pauseOnLastFrame = value;
MediaEndedHandler = value
? new PauseOnLastFrameHandler()
: new NullMediaEndedHandler();
}
}
public IMediaEndedHandler MediaEndedHandler = new NullMediaEndedHandler();
}
Then:
private void OnMediaEndedCommand()
{
if (GeneralSettings.MediaEndedHandler.AlternateHandling(MediaPlayer))
return;
if (PlayListViewModel.FilesCollection.Last().Equals(PlayListViewModel.FilesCollection.Current) && !Repeat)
{
ChangeMediaPlayerSource(PlayListViewModel.ChangeCurrent(() => PlayListViewModel.FilesCollection.MoveNext()));
MediaPlayer.SetMediaState(MediaPlayerStates.Stop);
return;
}
ChangeMediaPlayerSource(PlayListViewModel.ChangeCurrent(() => PlayListViewModel.FilesCollection.MoveNext()));
}
This way, if your setting is, for example. an enum instead of a bool, you can specify a different implementation of the interface for each possible value.
I am building an application to teach myself MVVM and with some Googling (and some trial an error) I have managed to get to the point where I can open a second window from the ViewModel but not to pass a variable from one page to the other. This is my ViewModel.
public VendorSelectViewModel()
{
Ping ping = new Ping();
PingReply pingresult = ping.Send("192.168.1.10");
if (pingresult.Status.ToString() == "Success")
{
LoadVendorsAsync();
}
else
{
LoadVendors();
}
NextCommand = new RelayCommand(NextWindow);
}
public ICommand NextCommand { get; private set; }
void NextWindow()
{
Console.WriteLine(selectedVendor.VendorName);
Messenger.Default.Send(new NotificationMessage("NextWindow"));
}
In my view I have this
public VendorSelectWindow()
{
InitializeComponent();
_vm = new Biz.Invoicer.VendorSelectViewModel();
DataContext = _vm;
Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived);
}
private void NotificationMessageReceived(NotificationMessage msg)
{
if (msg.Notification == "NextWindow")
{
var invoicerWindow = new InvoicerWindow();
invoicerWindow.Show();
}
}
So I know (or I think I know) this may not be a "Best Practice" but I will come back to this and refactor as I get to know the MVVM patern and MVVM Light better. Currently I am trying to pass a variable from the ViewModel of the first page (VendorSelectViewModel) to the Second page (InvoicerWindow) but I haven't managed to the syntax correct.
What do I need to do to pass a variable from one page to the next?
First of all you can pass an arbitrary object as the parameter of the IMessenger.Send<TMessage> method - the TMessage type parameter is not restricted. E.g.:
//ViewModel:
void NextWindow()
{
//...
int someValue = 10;
Messenger.Default.Send(someValue);
}
//View:
public VendorSelectWindow()
{
//...
Messenger.Default.Register<int>(this, MessageReceived);
}
private void MessageReceived(int value)
{
//...
}
If however you find the NotificationMessage class particularly useful in your case you could make use of the generic NotificationMessage<T> version, which exposes additional property Content of arbitrary type T:
//ViewModel:
void NextWindow()
{
//...
int someValue = 10;
Messenger.Default.Send(new NotificationMessage<int>(someValue, "Notification text"));
}
//View:
public VendorSelectWindow()
{
//...
Messenger.Default.Register<NotificationMessage<int>>(this, MessageReceived);
}
private void MessageReceived(NotificationMessage<int> message)
{
var someValue = message.Content;
//...
}
Or, if that does not suit you, you could create your own class deriving from NotificationMessage and exposing additional members and use that as the message object.
Instead of passing a NotificationMessage to the messenger, you could pass an instance of your own custom type which may carry as many values you want:
void NextWindow()
{
Console.WriteLine(selectedVendor.VendorName);
Messenger.Default.Send(new YourPayload() {WindowName = "NextWindow", Parameter = "some value..:");
}
...
public VendorSelectWindow()
{
InitializeComponent();
_vm = new Biz.Invoicer.VendorSelectViewModel();
DataContext = _vm;
Messenger.Default.Register<YourPayload>(this, NotificationMessageReceived);
}
private void NotificationMessageReceived(YourPayload msg)
{
if (msg.WindowName == "NextWindow")
{
string param = msg.Parameter;
var invoicerWindow = new InvoicerWindow();
invoicerWindow.Show();
}
}
YourPayload is a custom class with two properties, WindowName and Parameter.
Ok so I am trying to pass a boolean from my Login form to my Home form, normally this would be fine for me and I would just use a property. However I thought I could use a similar method this time but I am implementing the singleton factory on the forms.
Here is the Login code relevant to this:
The AdminAccess property gets set fine and I have checked the value is correct.
private bool adminAccess;
public bool AdminAccess
{
get { return adminAccess; }
private set { adminAccess = value; }
}
private void btnLogin_Click(object sender, EventArgs e)
{
//Some Code Does Stuff
OpenHome();
}
private void OpenHome()
{
HomeForm CreateHomeForm = HomeForm.HomeUI;
CreateHomeForm.StartupHome = this;
//Trying to set the property.
CreateHomeForm.AdminPermissions= this.AdminAccess;
CreateHomeForm.Show();
this.Hide();
}
Here is the relevant code from the Home form:
public HomeForm()
{
InitializeComponent();
//just to check what is in the property quickly
textBox1.Text = AdminPermissions.ToString();
}
private bool adminPermissions;
public bool AdminPermissions
{
private get { return adminPermissions; }
set { adminPermissions = value; }
}
public Form StartupHome
{
set;
get;
}
private static HomeForm homeUI;
public static HomeForm HomeUI
{
get
{
if (homeUI == null || homeUI.IsDisposed)
{
homeUI = new HomeForm();
}
return homeUI;
}
}
The value gets reset when the HomeUI if loop runs as a new instance of the form is created. I can't seem to think how to modify this to get a working solution. As you can tell I am fairly amateur so I'm just looking for a quick and clean solution to this :)
Thank you very much for your time in advance!
You assign the value in the constructor, BEFORE the AdminPermissions property is actually set. Change your code like this
public class HomeForm
{
public HomeForm()
{
InitializeComponent();
}
private bool adminPermissions;
public bool AdminPermissions
{
get { return adminPermissions; }
set {
adminPermissions = value;
textBox1.Text = value.ToString();
}
}
...
}
Try setting the textBox1.Text value in one of the Form events. Try Loaded first, then Activated. You're resetting it to false every time in your constructor!