Hi all I'm trying to get to grips with using MVVM, but I'm having a hard time :(, firstly for my question, I'm using the code provide in this MVVM article as a template for my learning.
My question is simple how do expose independent commands, in this case he has create a list of hyperlinks, but how do i create a single button that's fixed and does the same as the 'create new customer' link.
I created something like this(was added to the MainWindowViewModel.cs):
public CommandViewModel exposedCommand
{
get
{
return new CommandViewModel(
Strings.MainWindowViewModel_Command_CreateNewCustomer,
new RelayCommand(param => this.CreateNewCustomer())
);
}
}
and then in the xaml document i created a new button, this was added to the MainWindow.xaml
<Button
Content="Button"
Height="23"
HorizontalAlignment="Left"
Margin="6,303,0,0" Name="button1" VerticalAlignment="Top" Width="150"
Command="{Binding Path=exposedCommand}"
/>
I am not to sure if I'm missing something, or what I am where going wrong,
Soz if I sounding a bit naive I have only just started using MVVM and routed commands and so.
Oh another thing it does load the link it just doesn't create the tab, in other words if you would to add
Console.Writeline("HERE");
to the exposedCommand method
It would print out 'HERE' it just won't do anything when you click the button.
Thanks Any Help would be so appreciated.
Your XAML code is correct.
I also started off with Josh Smith's MVVM article.
Below is a stripped down example of how I implement Commands in my ViewModels:
public class ProjectViewModel : ViewModelBase
{
// Private variable for holding save command
private RelayCommand _saveCommand;
// Other fields here
// Constructors and properties and stuff here
// Command Property for Save button. Bind XAML to "SaveCommand"
public ICommand SaveCommand
{
get
{
if (_saveCommand == null) // Init command on first get
_saveCommand = new RelayCommand(param => this.SaveChanges(), param => this.CanSave);
return _saveCommand;
}
}
/// <summary>
/// Method called when save command is executed
/// </summary>
private void SaveChanges()
{
// Save logic here...
}
/// <summary>
/// Predicate for determining if SaveCommand is enabled
/// </summary>
private bool CanSave
{
get
{
return true; // Replace with SaveCommand predicate logic
}
}
}
If it still does not work, check you runtime output for BindingErrors. If there is a BindingError that implies that the View cannot find the SaveCommand, then your ViewModel is not correctly set to be the DataContext of the View. Let me know in the comments if this is the problem.
You can bind command to only those objects that has an implementation of ICommand interface.
In your example you are binding with view model object.
Instead of this create a property in view model that is a type of RelayCommand and bind this with button.
It should work.
The first thing that concerns me is your the code inside the getter of you property. You're returning a new object EVERY TIME the exposedCommand is accessed. That's not really recommended, you should store that in a backing property like so:
CommandViewModel _exposedCommand;
public CommandViewModel exposedCommand
{
get
{
if (_exposedCommand == null)
{
_exposedCommand = new CommandViewModel(
Strings.MainWindowViewModel_Command_CreateNewCustomer,
new RelayCommand(param => this.CreateNewCustomer()));
}
return _exposedCommand;
}
}
That being said the typical way to present your desired ICommand property is something like this:
RelayCommand _exposedCommand;
public ICommand exposedCommand
{
get
{
if (_exposedCommand == null)
_exposedCommand= new RelayCommand(param => this.CreateNewCustomer());
return _exposedCommand;
}
}
Related
Im using xamarin forms with freshmvvm framework.
I would like to know how I can skip using xaml, and just access binding data from code behind in c#.
Are there any code samples that could help?
Although this goes against the principles of MVVM there is of course a way to do it.
Without a MVVM framework you would just create a ViewModel by hand and set the BindingContext (documentation) yourself. The 'only' thing (in regard to this) a MVVM framework does for you is set that binding up automatically so you're not bothered with writing the same code over and over again.
So, imagine you have this ViewModel, note I user PageModel to match the FreshMvvm naming:
// SamplePageModel.cs
public class SamplePageModel
{
public string Foo { get; set; } = "Bar";
}
Now in my Page, I set the BindingContext like this:
// SamplePage.cs
// ... Skipped code, just constructor here:
public SamplePage()
{
InitializeComponent();
BindingContext = new SamplePageModel();
}
Now you can bind to any property of SamplePageModel.
FreshMvvm does this part automagically.
If, for whatever reason, you would like to access the ViewModel/PageModel directly, just do the reverse. Somewhere in your Page or code-behind you can do:
// ... Some code here
var pageModel = BindingContext as SamplePageModel;
// ... More code here
Now if pageModel isn't null there you have your data-bound and filled PageModel!
I found Gerald's answer helpful, but I found that you need to override this event in your page vs doing the as in the constructor:
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
var pageModel = BindingContext as YourFreshMVVMPageModel;
// Modify the page based on the pageModel
}
The PageModel construction seems to take place after the page Constructor, and this Event seems to fire at the right time and still make the page do what you want.
I'm trying to implement Unity in a WPF MVVM application, but I'm missing the big picture.
At this moment I have created a bootstrapper like this:
public class MainBootstrapper : Bootstrapper<MainViewModel>
{
private UnityContainer container;
protected override void Configure()
{
container = new UnityContainer();
container.RegisterType<IServiceLocator, UnityServiceLocator>(new ContainerControlledLifetimeManager());
container.RegisterType<IWindowManager, WindowManager>(new ContainerControlledLifetimeManager());
container.RegisterType<IEventAggregator, EventAggregator>(new ContainerControlledLifetimeManager());
}
protected override object GetInstance(Type service, string key)
{
if (service != null)
{
return container.Resolve(service);
}
if (!string.IsNullOrWhiteSpace(key))
{
return container.Resolve(Type.GetType(key));
}
return null;
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return container.ResolveAll(service);
}
protected override void BuildUp(object instance)
{
container.BuildUp(instance);
}
}
How what is the best way to use this?
This code currently works:
public class MainViewModel : PropertyChangedBase
{
public MainViewModel()
{ }
[Dependency]
public Sub1ViewModel Sub1VM { get; set; }
[Dependency]
public Sub2ViewModel Sub2VM { get; set; }
}
the MainView has this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentControl Grid.Row="0" Name="Sub1VM" />
<ContentControl Grid.Row="1" Name="Sub2VM" />
</Grid>
First of all: the code that I shared, is this the correct way of using Unity + Caliburn?
Now let's say that my Sub1VM uses a model 'M1', but Sub2VM needs to use the same model to display information but not by making another instance of model M1. (singleton)
How does this work now? Show I use a IServiceLocator in each viewmodel constructor? Could somebody share a code sample to explain it?
First of all i agree with McDonnellDean that you should read the article about the Screens, Conductors and Composition (if i were you i would read all the articles before that too to understand how Caliburn.Micro works.). Besides that, you implemented Unity correctly and you can check Unity as IoC Container for Caliburn.Micro for more information. On the other side you are mixing two concepts here, namely Dependency Injection and MVVM. Regarding your question about the model, i would also prefer constructor injection, and if you want a single instance of the model, perhaps you can inject a Factory that creates that model for you and wrap it into two different view models and expose it through the two different properties. At last i really encourage you to read the tutorials (start here), at least the basic topics.
I don't know Unity in particular but your configuration looks correct.
As for your injection points. I would say that rather than doing property injection you should do constructor injection. What you are doing is fine, however you may want to look up screens and conductors, these allow you to add life-cycle to your ViewModels. Typically it would look like this:
Bootstrapper opens ShellViewModel
ShellViewModel takes in MainViewModel via Ctor injection as an IConductorOneActive
MainViewModel takes a collection of IScreens.
ShellViewModel calls MainViewModels activate method on MainViewModel.
See Screens, Conductors and Composition. As I stated above, your way is fine but it is a little on the manual side and means you have to wire everything by hand.
I'm inexperienced, especially at MVVM, but trying to use ReactiveUI, and I'm not understanding the examples that I'm finding that demonstrate ReactiveCommand. I have used ICommand / DelegateCommand one time before, but this is different, and I'm not getting it.
What I'm trying to do is really simple. Click a button in the view, and have that execute a method in the view model. The examples that I'm finding all involve IObservable<>, and I don't get that, as they don't explanations that are geared to the total noob that I am.
Basically, I'm trying to use this as a learning experience, and what I'd ideally like to do is bind the button's Command property in xaml to a command (however that works, I don't know), which causes a method to execute. No collections, I'd just be passing a single int variable.
Thanks for the help. I really appreciate it.
Edit - Below appears code using Paul Betts' suggestions:
C#
public ReactiveCommand AddToDailyUsed { get; protected set; }
public MainPageVM()
{
Initialize();
AddToDailyUsed = new ReactiveCommand();
AddToDailyUsed.Subscribe(AddToTodayUsedAction => this.AddToDailyUsedExecuted());
}
private object AddToDailyUsedExecuted()
{
MessageBox.Show("AddToDailyUsedAction");
return null;
}
private void AddToDailyUsedAction(object obj)
{
MessageBox.Show("AddToDailyUsedAction");
}
XAML
<Button Content="{Binding Strings.add, Source={StaticResource LocalStrings}}"
Command="{Binding AddToTodayUsed}"
Margin="-5,-10, -10,-10"
Grid.Row="3"
Grid.Column="2" />
Obviously I'm missing something. I inserted break points at the AddToDailyUsedExecuted and AddToDailyUsedAction methods, and they are never reached.
Edit Constructor for code behind the view:
MainPageVM mainPageVM = new MainPageVM();
public MainPage()
{
InitializeComponent();
Speech.Initialize();
DataContext = mainPageVM;
ApplicationBar = new ApplicationBar();
TaskRegistration.RegisterScheduledTask();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
//Shows the rate reminder message, according to the settings of the RateReminder.
(App.Current as App).rateReminder.Notify();
}
So, ReactiveCommand is itself an IObservable<object> - in this case, you can conceptualize IObservable as an Event - this Event fires when the command is invoked (i.e. when the button is pressed). So, in your constructor, you might write:
MyCommand = new ReactiveCommand();
MyCommand.Subscribe(param => this.MyCommandHasExecuted());
However, what's neat about IObservable that isn't true about regular events, is that you can use LINQ on them:
// Now, MyCommandHasExecuted only gets run when the UserName isn't null
MyCommand.Where(param => this.UserName != null)
.Subscribe(param => this.MyCommandHasExecuted());
Update: Your Xaml binds to AddToTodayUsed but your ViewModel command is called AddToDailyUsed. Could that be it?
I'm using MVVM Light Toolkit and in my View, I have a function that takes a screenshot and returns byte array of that screenshot. Since taking an screenshot (using UIElements) is related to view not ViewModel.
byte[] TakeScreenShot(Canvas sourceUiElement)
I need to get the return value of the function in my ViewModel but I can't come up with a proper way of doing it.
I other hand if I wanted to do move this function to my ViewModel, I need to have access to that element in view but without referencing the View in my ViewModel (maybe as argument or something to a Command?)
Since this question is tagged as MvvmLight, then here is an MvvmLight Toolkit answer. Use said toolkit's Messenger class. Simply define the following message classes somewhere in your application:
public class TakeScreenshotMessage : MessageBase { }
public class ScreenshotTakenMessage : GenericMessage<byte[]>
{
public ScreenshotTakenMessage (byte[]content) : base(content) { }
public ScreenshotTakenMessage (object sender, byte[]content) : base(sender, content) { }
public ScreenshotTakenMessage (object sender, object target, byte[]content) : base(sender, target, content) { }
}
In your code-behind's constructor, register for the TakeScreenshotMessage like this:
Messenger.Default.Register<TakeScreenshotMessage>(this, (msg) =>
{
byte[] bytes = this.TakeScreenShot(someCanvas);
Messenger.Default.Send(new ScreenshotTakenMessage(bytes));
});
And in your view model, register for the ScreenshotTakenMessage like this:
Messenger.Default.Register<ScreenshotTakenMessage>(this, (msg) =>
{
byte[] bytes = msg.Content.
//do something with your bytes
});
Now you can take a screen shot at any time simply by calling the following from anywhere in your application (i.e. view models, views, helper classes, etc.):
Messenger.Default.Send(new TakeScreenshotMessage());
I would bind the TakeScreenShot with the click event of the button or something in the code behind, have a property on the ViewModel called Snapshot for example, and in the click event, you get the byte[] array, assign it to the ViewModel's property Snapshot, like so in the code behind.
public void ButtonOnClick(object sender, EventArgs e)
{
var myViewModel = this.DataContext;
myViewModel.Snapshot = this.TakeScreenShot(someCanvas);
}
Depends on how strict you are with MVVM, and some might disagree, I think it is perfectly valid for your view to reference your viewmodel, aka you must know the context you are binding to anyways, but not the other way around. It is like manually binding to me.
I am looking for some help and I hope that some good soul out there will be able to give me a hint :)
I am building a new application by using MVVM Light. In this application, when a View is created, it instantiates the corresponding ViewModel by using the MEF import.
Here is some code:
public partial class ContractEditorView : Window
{
public ContractEditorView ()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
}
[Import(ViewModelTypes.ContractEditorViewModel)]
public object ViewModel
{
set
{
DataContext = value;
}
}
}
And here is the export for the ViewModel:
[PartCreationPolicy(CreationPolicy.NonShared)]
[Export(ViewModelTypes.ContractEditorViewModel)]
public class ContractEditorViewModel: ViewModelBase
{
public ContractEditorViewModel()
{
_contract = new Models.Contract();
}
}
Now, this works if I want to open a new window in order to create a new contract... or in other words, it is perfect if I don't need to pass the ID of an existing contract.
However let's suppose I want to use the same View in order to edit an existing contract. In this case I would add a new constructor to the same View, which accepts either a model ID or a model object.
"Unfortunately" the ViewModel is created always in the same way:
[Import(ViewModelTypes.ContractEditorViewModel)]
public object ViewModel
{
set
{
DataContext = value;
}
}
As far as I know, this invokes the standard/no-parameters constructor of the corresponding ViewModel at composition-time.
So what I would like to know is how to differentiate this behavior? How can I call a specific constructor during composition time? Or how can I pass some parameters during the Import?
I really apologize if this question sounds silly, but I have only recently started to use MEF!
Thanks in advance,
Cheers,
Gianluca.
You CAN do this. Check out the Messenger implementation in MVVM-Light. You can pass a NotificationMessage(Of Integer) to send the right ID to the view model. The view model has to register for that type of message, and load it when a message is sent.
MEF Imports by default only have a parameterless constructor.