I am new to MVVM and need help on below scenario.
I have a Stack panel added on my view, now I have to add few controls dynamically to this stack panel through viewmodel. For this I need a handle of stack panel in my viewmodel. Can anybody please guide me how I can access stack panel in my viewmodel.
I read in other bloges that it can be done by using Dependency property. but still I am not able to find way to solve this issue.
Couple of things to note first. The intention of the ViewModel in the MVVM pattern is to provide separation from the View. Therefore, your ViewModel should have no knowledge of the View itself nor the controls contained in the View. Secondly, what you should be attempting to do is have your View bind to a property of your ViewModel (with the understanding that your ViewModel serves as the DataContext of your View). Normally, you would bind a control's ItemsSource property to some collection in the ViewModel. However, you will notice the StackPanel does not implement the ItemsSource dependency property. Instead, use ItemsControl in place of your StackPanel. I would suggest some additional reading on the MVVM pattern and the binding mechanics for additional clarification.
Totally agreed with Backlash,
It seems that your ViewModel and your View are too much coupled;
There are a bunch of resources on the Internet, but here are some I preferred:
Jason Dolinger presentation video on MVVM
John Smith article introducing MVVM
I have done this before with a user control. I've had a collection of objects that i needed to dynamically to controls in a StackPanel. You can also do it with any control...I'll use a TextBlock in this example.
Create a data template with the control you want wrapped in a stack panel:
(MyText is a property in the object of the collection... see below)
<DataTemplate x:Key="MyTemplate">
<Grid Margin="0">
<StackPanel>
<TextBlock Text="{Binding Path=MyText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</TextBlock>
</StackPanel>
</Grid>
</DataTemplate>
Then the key is to bind to a collection of objects using an ItemsControl:
(The collection is on your viewModel)
<ItemsControl
ItemsSource="{Binding ACollection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemTemplate=" {StaticResource MyTemplate}" Background="Transparent">
</ItemsControl>
So for example if there are 3 items in "ACollection" there will be 3 TextBlocks stacked on top of each other if there are 5 in the collection there will be 5 TextBlocks etc.
Thanks All for your help, Here I solved the problem
In view model I have created ObservableCollection of FrameWorkElement type, which can hold any other controls which will be decided at runtime. Control can be a text box or button.
Public ObservableCollection < FrameWorkElement > Test
{
get{....} set{...}
}
Now I can add/set any other control to Test
Tets.Add(new TextBox()); Or Button , this will be decided at runtime.
Now bind this "Test" to ItemsControl.
<ItemsControl x:Name="itemsControl" ItemsSource={Biding Test}>
</ItemsControl>
Related
Is there a way to implement a shared TitleView component in Xamarin.Forms AppShell? I've tried a couple of approaches but it's not working as I intended.
What I'm trying to achieve is something like the following:
App Shell with a few tabs and a common Shell TitleView
The titleView is just a ContentView (let's call it Exposure) with a label to display the result of a calculation and a refresh button to fetch data and recalculate
Changing Tab shouldn't affect the state of the TitleView
What I've tried:
Initialize one instance of the Exposure component (View and ViewModel) and configure it on the DI framework to use that instance only (singleton).
When the Pages are initialized I get the single instance of the Exposure component and assign it to the Shell.TitleView property.
By doing this I was hoping that the Exposure state would be consistent across the tabs (single instance after all...), but what happens is that when I hit the refresh button it only refreshes the calculation on the current tab Exposure component, changing tab will present me with the Exposure component with old state. I'm surprised this is not supported out of the box (configure titleView at Shell level) but I might be missing something.
Might not be relevant but I'm using ReactiveUI (MVVM) and Splat (dependency injection)
The next thing I'm willing to try is to trigger a refresh when each page re-appears but that feels dodgy.
You can create a base ContentPage and set the style of TitleView of it .
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="xxx.BaseContentPage">
<NavigationPage.TitleView>
<StackLayout>
//...
</StackLayout>
</NavigationPage.TitleView>
<ContentPage.Content>
<StackLayout>
//...
</StackLayout>
</ContentPage.Content>
</ContentPage>
Can I quickly confirm if this is a best practice or I should be rethinking my process with MVVM. (I am new to this)
<ComboBox DataContext="{Binding MemberMain, Source={StaticResource Locator}}" ItemsSource="{Binding PayMethodList}" Text="{Binding DataContext.Member.MM_PaymentMethod, ElementName=TabItemClient}" Margin="0,0,15,0"/>
I am binding a combobox itemssource to one view model and the text to another.
Thanks in advance Scott
The only thing glaring that I see here is the DataContext binding. Do you really need this?
Other than that. If it works and remains concise, if you can swap bits in/out with little issue, then it is fine.
Posting your view model may help further assessment.
I am totally new to Windows 8 development and I am now facing an issue mixing touch and keyboard navigation using MVVM Light.
So I have a list of view models in a grid view and whenever one of those is selected, navigation to the selected view model is activated. This works totally fine with touch or a mouse, but with a keyboard it can get really confusing. Indeed, the natural behavior would be to navigate the list with the arrows and hit enter when I want to display the item, but here instead, navigation will be activated when simply changing item with the arrow keys which is really confusing for the user.
So how could I do so the navigation could be activated on selection with touch and mouse and with a combination of selection and enter key with the keyboard?
Here is the code I use.
ViewModel:
public ReleaseViewModel SelectedRelease
{
get
{
return selectedRelease;
}
set
{
if(selectRelease != value)
{
selectedRelease = value;
}
// Navigation code here
}
}
View:
<GridView
ItemsSource="{Binding Releases}"
ItemTemplate="{StaticResource ReleaseTemplate}"
ItemContainerStyle="{StaticResource GridViewItemStyle}"
Grid.ColumnSpan="2"
Grid.Row="2"
Padding="116,0,40,46"
SelectedItem="{Binding SelectedRelease, Mode=TwoWay}"/>
In my opinion, coding with the MVVM pattern does not mean that everything code-related should be done in the model. Operations which is related UI beaviors (like navigation) should still be done in the view (the codebehind), by using the available events from the control. Like the GridView's events mouse and keyboard events.
Many may not agree with me on that, but after working by the MVVM pattern for several years in both WPF and Silverlight, I must say that a good combination between the UI-behavior (view) and the control's logic/functionability (model), you will also be forced to put several stuff which concerns the UI only to the codebehind. At least, this is my opinion.
What you could do is to create a class which inherits GridView (let's call it MyDataGrid).
Then you can use the OnKeyDown override and have the navigation go vertica when pressing enter.
You can actually make the MyDataGrid look and behave "out-of-the-box" just like you want so there are no extra code if you want to use the same grid behavior another place in your app (or another app).
The best way I finally found is to use some code behind. But instead of directy navigating from the UI I kept navigation logic in the view models.
So I simply hooked up the ItemClick event from the GridView and in the event handler I casted the Page data context to my view model and then I simply executed the command from the view model. This is not easy to maintain but it surely preserve the separation of concerns of MVVM.
private void GridView_ItemClick(object sender, ItemClickEventArgs e)
{
MyViewModel vm = (MyViewModel)this.DataContext;
if(vm.NavigateToSelectionCommand.CanExecute(null))
{
vm.NavigateToSelectionCommand.Execute(e.ClickedItem);
}
}
Still I hope a cleaner and more maintainable solution will come up with time.
Can anyone tell me what the actual syntax is for EventToCommand class. From what I believe is that EventToCommand class works with Silverlight / WPF and WP7, hence I think its a better choice to go down.
From what I believe, I can add any click event and get it forced into my ViewModel, but I am having an issue in finding the best way to do this.
I know you can add it without Blend, but are there snippets available?
Or is there an easier way to add it via VS 2010? Any help or if anyone knows of a good tutorial on this would be great.
Suppose you use .NetFramework4:
First add namespace:
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform"
Syntax for the Loaded event.
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<cmd:EventToCommand Command="{Binding Mode=OneWay, Path=LoadedCommand}"
PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
I updated my project and it looks like they moved the command to:
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform"
0) if you dont't know WPF and MVVM, then read Josh Smith article about WPF and MVVM pattern https://msdn.microsoft.com/en-us/magazine/dd419663.aspx
1) In your project add package (through NuGet) MvvmLightLibs
2) add reference to System.Windows.Interactivity
3) In "View" XAML add:
a)
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:command="http://www.galasoft.ch/mvvmlight"
b)
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<command:EventToCommand Command="{Binding OnClosingCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Window>
4) In ViewModel add necessary property
public ICommand OnClosingCommand
{
get
{
return new RelayCommand(() => SomeMethod());
}
}
P.S. In your View should be specified DataContext (XAML)
<Window.DataContext>
<vm:MainWindowViewModel/>
</Window.DataContext>
It is work. I myself just learned.
I'm using MVVM in a WPF app. I'm very new to both. Let me state that I am not a purist in the MVVM pattern, I am trying to use as many best practices as I can but am trying to make what I think are reasonable compromises to make it work in our environment. For example, I am not trying to achieve 0% code in my View code-behind.
I have a couple of questions about best practices.
1) I understand I don't want my VM to know about the attached View, but is it reasonable for the View to have a reference to its VM?
2) If a control in a View opens another View (such as a dialog) should I handle this in the View? It seems wrong to handle it in the VM since then the VM has some knowledge of a specific View.
1) The View has definitely a reference to the ViewModel through the DataContext. And you are allowed to cast the DataContext in your View:
public class ShellView : Window
{
…
public ShellViewModel { get { return DataContext as ShellViewModel; } }
This isn’t a violation with the Model-View-ViewModel pattern.
.
2) You are right. A ViewModel shouldn’t open another View. A better approach is to use Controllers. They are responsible for the Workflow of an application.
If you are interested in more detailed information then you might have a look at the WPF Application Framework (WAF).
1) Here are two simple practices for View's "knowing about" a ViewModel. It's reasonable for a View to know about a ViewModel (for Data Binding) -- but you may not need it in your case. See if either of these approaches help solve your problem. There are other ways, but these should be simple enough:
public View(ViewModel vm)
{
View.DataContext = vm;
}
public Bootstrapper(View v, ViewModel vm)
{
v.DataContext = vm;
//or, if you want it to have no parameters
View v = new View();
ViewModel vm = new ViewModel();
v.DataContext = vm;
}
The first option isn't bad if you have a service location tool, but there is a flavor of MVVM that doesn't like any code in the View's Code-Behind. The second option isn't bad either, should be simple enough for your task.
2.) This question can be a bit of a sticky point in MVVM design. If we are talking about a general Win32 MessageBox, I will often separate that logic into an additional object and put it in the VM. This way tends to a little more clear. (For example, I have selected an item in a ListBox, I have attached a Delete ICommand to that action, and in my ViewModel when this ICommand is Executed, I will poke my MessageBoxObject to ask if the user "wants to really delete" this item). More advanced "Dialogs" would use additional ViewModels and DataTemplates for those ViewModels. I prefer the Mediator approach.
1). The view will need a reference to the view model at some level, since the viewmodel will act as the view's datacontext.
2) One way to handle this is to have a generalized viewmodel representing a dialog, that is owned by the main viewmodel (the one being used as the views datacontext.)
You can use a command to crate a new instance of a dialog viewmodel, which will have a corresponding datatemplate defined in your resources. This template will be set to bind to the dialogviewmodel type.
Quite late, but I think this is tricky enough to deserve lots of different perspectives.
I understand I don't want my VM to know about the attached View, but
is it reasonable for the View to have a reference to its VM?
As already answered, a proper View-ViewModel arrangement involves the ViewModel being assigned as the View's DataContext property. That allows DataBindings to be "automagically" established from declarative XAML, or fine-tuned via code behind.
Sometimes, you'll be tempted to write, in your code behind, something like this:
var dc = DataContext as CleverViewModel;
CleverViewModel.CleverProperty.Add(someValue); // just a simple example
I believe the proper way to achieve this sort of things is NOT to cast DataContext, but instead:
Have some dedicated control in View, for example an ItemsControl with its ItemsSource two-way databound to some property in viewmodel:
<ItemsSource x:Name="cleverControl" Visibility="Collapsed" ItemsSource="{Binding CleverProperty, Mode=TwoWay}"/>
Cast the bound property instead of the whole ViewModel, in code behind:
var collection = (ObservableCollection<double>)cleverControl.ItemsSource;
collection.Add(someValue);
Note the important difference: the second approach in this example doesn't require the View to know the ViewModel type, it only needs a property named CleverProperty of type ObservableCollection<double>. This allows me to have polymorphic or even duck-typed ViewModels.
If a control in a View opens another View (such as a dialog) should I
handle this in the View? It seems wrong to handle it in the VM since
then the VM has some knowledge of a specific View.
This shouldn't happen in strict MVVM, and its not difficult to avoid using DataTemplates. DataTemplates map a given type of DataContext to a given type of view, so anytime the datacontext of a ContentControl changes, its display also changes, provided that you have a DataTemplate for that type:
A control in the view could send a command to the ViewModel, which in turn would update some of its own properties, that would be reflected by the view.
A View could contain another View, outside the knowledge of the ViewModel. In this case, the code behind can manipulate the datacontext of the contained view.
There are more subtleties, but I have been using this approach with good results. Hope this helps someone.
Build Your Own MVVM Framework
I found the approach suggested by Rob Eisenberg very interesting.
Key points:
Convention over configuration
ViewModel first
Which is very similar to ASP.NET MVC philosophy.
I highly recommend watching the video.