I have to create in my XAML file a static resource.
<Window.Resources>
<vm:ViewModel x:Key="viewModel" />
</Window.Resources>
I need this static resource to get the items for my combobox
ItemsSource="{Binding Source={StaticResource viewModel}, Path=GetItems, Mode=TwoWay}"
But how can I give the ViewModel (constructor) a instance of my code behind class?
If I understand this correctly, you are violating the MVVM pattern.
You should never provide items from the ComboBox into your VM. You should rather provide the items from you VM and bind it to the Combobox, and the you don't have problems accessing the items.
As far as I understand you want to bind your view and viewmodel according to the MVVM pattern.
You should not reference your viewmodel directly in your view, otherwise you have a strong coupling between them. According to the MVVM pattern, you should couple them by the DataContext
In code behind (for example in file App.xaml.cs) it looks like that
yourWindow.DataContext = yourViewModel
Then in your viewmodel class you will have a property named GetItems
Finally in your window you bind your listbox to GetItems
ItemsSource="{Binding GetItems, Mode=TwoWay}"
Well, you can do it from the code, I mean everything from the code, or you can
try (depends on how your app architcted) , by using ObjectDataProvider.
For example:
<ObjectDataProvider ObjectType="{x:Type ViewModel}" x:Key="viewModel">
<ObjectDataProvider.ConstructorParameters>
<StaticResource ResourceKey="dataProvider"/>
</ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider >
In this case, naturally, the parameter you pass to ctor of the povoder, have to be a resource too.
Related
CollectionViewSource class is supposed to provide a so-called "view" over data. This includes data filtering, sorting and grouping.
Now, one may think, that this is a responsibility of a View in MVVM architecture, but very often it is user, who decides, what kind of grouping, sorting or filtering he wants. These are business decisions, which belongs to viewmodel. Moreover, filtering is performed by taking an element and deciding, whether it matches filter or not, and that is definitely viewmodel's responsibility (possibly then passed to a service).
It seems then, that CollectionViewSource is a good candidate to be directly exposed from the viewmodel, because the latter then have full control over its properties (eg. GroupDescriptions). But even though this class resides in Windows.Data namespace, it is still in PresentationFramework assembly and I feel really uncomfortable to reference it from my BusinessLogic assembly, because I'm hardly tying it to a specific (nomen omen) presentation framework.
From what I saw, the most common place for CollectionViewSource are control's (window's) resources from which (surprisingly) I can bind to the viewmodel. But then manipulating filtering, sorting and grouping is a mess, because you have to push information manually between view and viewmodel. Just for one example:
<CollectionViewSource x:Key="SuggestionItems" Source="{Binding Suggestions}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="{Binding SuggestionGroupByProperty}"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
This will not work, because PropertyGroupDescription.PropertyName is not a DependencyProperty. So I'd probably have to design my own Xaml extension to be able to bind such information from viewmodel to a view.
I failed to find any tutorial or documentation on how is ColletionViewSource supposed to fit into MVVM/WPF framework. I actually got an impression, that this is not really too much thought-through, because, for instance, placing the CollectionViewSource anywhere outside resources requires some really nasty shenanigans to simply push collection inside.
For example (mind the SelectedItem):
<DataGrid x:Name="grid"
AutoGenerateColumns="False"
ItemsSource="{Binding}"
SelectedItem="{Binding Path=DataContext.SelectedItem, RelativeSource={RelativeSource AncestorType={x:Type Window}}, Mode=TwoWay}">
<DataGrid.DataContext>
<CollectionViewSource x:Name="myViewSource" Source="{Binding MyCollection}" Filter="CollectionViewSource_OnFilter">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Container" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</DataGrid.DataContext>
<!-- (...) -->
</DataGrid>
So how the CollectionViewSource should canonically fit into the MVVM pattern, so that viewmodel has enough control over it? And if it shouldn't, then how this scenario (collection grouping, sorting, filtering) should actually look in MVVM?
I have a ViewModel which that is defined in my application resources, this ViewModel has a command called RunCommand
and in my MainWindow i am trying to bind that command to a button without setting the datacontext so i tried
<Button Command="{Binding Source={StaticResource ViewModel.RunCommand}}"/>
it showed an exception, however when i do the following things work fine
<Button DataContext="{Binding Source={StaticResource ViewModel}}" Command="{Binding RunCommand}"/>
what is wrong with the first part, and do i have to set the datacontext for such a simple task?
You are certainly not forced to change/set the DataContext just so you can bind a simple property.
Here's what you want
<Button Command="{Binding RunCommand, Source={StaticResource ViewModel}}"/>
Setting the datacontext is a good thing to do ... it takes away the voodoo of what object you're talking to. I believe all MVVM frameworks help you out with Locators, and when not using them, you can use your code behind.
It's just the way the language works.
I have a WPF window displaying different self-defined Views. So far I was able to use everything I learned about MVVM :)
Now I got to a new "problem": I have 10 entities of the same view in a bigger view. These ten view-entities contain a set of controls (textbox, combobox etc.) but are all consistent.
So how do I bind these Views to a ViewModel?
I thought about having 10 instances of the ViewModel in the "higher-level" ViewModel and give the views fix-defined the instances of the VM as datacontext.
My question is now --> Is there a easier (or more convienient) way to bind many (identical) views to their viewmodels?
Code-Example:
View Model:
private PanelViewModel _panelViewModel1 = new PanelViewModel();
public PanelViewModel PanelVM1
{
get { return _panelViewModel1; }
}
View-Example:
<myControls:vwPanel HorizontalAlignment="Left" x:Name="vwPanel1"
VerticalAlignment="Top" DataContext="{Binding Path=PanelVM1}"/>
What bothers me is that I would need this logic ten times for ten views?
UPDATE:
To answer some questions: I want to show one view 10 times (in my example) I defined my own view by inheriting from UserControl. So my vwPanel inherits from UserControl. The 10 vwPanels are just placed inside a StackPanel inside a Grid.
It's not about displaying data, as you pointed out, there would be a listview or a datagrid a better place to start. It's a special case where I need this much input-controls :/
UPDATE2: What I hoped for was more like defining a List of ViewModels and Bind my 10 Views to one of this List. But this will not work will it? At least I wouldn't know how to refernce one "special" entitiy in the list out of XAML...
Typically I use implicit DataTemplates for mapping Views to ViewModels. They can go in <Application.Resources>, <Window.Resources> or even in under specific elements only such as <TabControl.Resources>
<DataTemplate DataType="{x:Type local:PanelViewModel}">
<myControls:vwPanel />
</DataTemplate>
This means that anytime WPF encounters an object in the VisualTree of type PanelViewModel, it will draw it using vwPanel
Objects typically get placed in the VisualTree through an ItemsSource property
<ItemsControl ItemsSource="{Binding CollectionOfAllPanels}" />
or by using a ContentControl
<ContentControl Content="{Binding PanelVM1}" />
If I understand your question correctly, you have a collection of something that you what to represent visually. That is, you have several viewmodels that you want to define a single view for, but show X number of times. Your example shows you using a panel as your view for the "PanelViewModel"...what is the parent item's control for the vwPanel? Assuming you're using something like a ListBox, you can define a custom DataTemplate that contains your vwPanel and assign that DataTemplate to your ListBox.ItemTemplate.
For example:
<Window.Resources>
<DataTemplate x:Key="myVMTemplate" TargetType="{x:Type myViewModels:PanelViewModel}">
<myControls:vwPanel HorizontalAlignment="Left" VerticalAlignment="Top"/>
</DataTemplate>
</Window.Resources>
<ListBox ItemsSource="{Binding Path=MyCollectionOfPanelVMs}"
ItemTemplate="{StaticResource myVMTemplate}" />
I haven't verified that this works.
I'm new to WPF and using MVVM. I have a view in which I want to display different content according to what a user selects on a menu. One of those things is another user control Temp which has a view model (TempVM) so I am doing this:
<ContentControl Content="{Binding Path=TempVM}"/>
and TempVM (of type TempViewModel)is null until the user clicks a button. Its data template is this
<DataTemplate DataType="{x:Type vm:TempViewModel}">
<view:Temp />
</DataTemplate>
That's fine, but the other thing I want to do is show a listbox when a user clicks a different menu item. So I am trying to do
<ContentControl Content="{Binding Path=Missions}"/>
(Missions is an observable collection of MissionData) and trying to template it like this:
<DataTemplate DataType="{x:Type ObservableCollection(MissionData)}">
<StackPanel>
<ListBox ItemsSource="{Binding}" SelectedItem="{Binding Path=MissionData, Mode=TwoWay}" DisplayMemberPath="MissionName" SelectedValuePath="MissionId" />
<Button Content="Go"/>
</StackPanel>
</DataTemplate>
But the compiler doesn't like the type reference. If I try doing it by giving the template a key and specifying that key in the ContentControl it works but obviously I see the ListBox and button when there's no Missions. Obviously I could make a user control and viewmodel and follow the same pattern as I did for the TempVM but it seems over the top. Am I going the right way about this and what do I need to do?
From what i see is that you try to use a Collection as a dataobject which is in my opinion bad practice. Having a DataTemplate for a collection is also problematic, like you already have witnessed. I would advice you to use a ViewModel for your missions collection.
class MissionsSelectionViewModel
{
public ObservableCollection<Mission> Misssions;
public MissionData SelectedMission;
public ICommand MissionSelected;
}
and modify your datatemplate to
<DataTemplate DataType="{x:Type MissionsSelectionViewModel}">
<StackPanel>
<ListBox ItemsSource="{Binding Missions}" SelectedItem="{Binding Path=MissionData, Mode=TwoWay}" DisplayMemberPath="MissionName" SelectedValuePath="MissionId" />
<Button Content="Go" Command="{Binding MissionSelected}/>
</StackPanel>
</DataTemplate>
If I were to follow your pattern of implicit templates, I would derive a custom non-generic collection MissionDataCollection from ObservableCollection<MissionData> and use it to keep MissionData items. Then I would simply reference that collection in DataType. This solution gives other advantages like events aggregation over the collection that are useful.
However, it seems to me that the best solution is the following.
Add a IsMissionsListVisible property to your VM.
Bind the Visibility property of the ContentControl showing the list to the IsMissionsListVisible property.
Use a keyed DataTemplate resource.
Implement the logic that determines if IsMissionsListVisible. Supposedly it should be true when there is at least one mission in the selected item. But the logic may be more complex.
I would do it this way. In fact, I do it this way usually, and it gives several benefits. The most important is that I can explicitly control the logic of content visibility in various situations (e.g. async content refresh).
I am just learning XAML and programming for Windows Phone 7.
Im trying to create an itemtemplate for a WP7 Pivot Control. I was able to make a template which contains a listbox. Is it possible to access this listbox in the code-behind so I can fill it based on a collection of a custom class? Basically how it works is that I have a pivot control and each item in that control is a category. For each category thatis added, there is a list of items that belong to that category. I need to be able to populate the list on each pivot item with items of that category.
I searched for ideas on how to accomplish this, and I get a lot of examples on databinding, but Im not too familiar on how databinding works in XAML.
Would databinding be the way to go or can I somehow get a reference to the listbox and add the items myself?
Any help would be greatly appriciated!
Thank you
I've some considerations on subject:
1) If you fill Categories list via binding, then you don't have entry point where binding is guaranteed comleted (because binding executes in deferred fashion).
2) Working with ItemTemplate's content is more tricky and unreliable, than DataTemplate approach, and you should use it just in exclusive situations. LogicalTreeHelper and VisualTreeHelper classes will help you.
3) But I would recommend you to build your view based on DataTemplates as it is common practice in WPF. Do you really think that this code is pretty complicated?
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow">
<Window.Resources>
<DataTemplate x:Key="InnerItemDataTemplate">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
<DataTemplate x:Key="CategoryDataTemplate">
<StackPanel>
<ListView ItemsSource="{Binding InnerItems}"
ItemTemplate="{StaticResource InnerItemDataTemplate}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ListView ItemsSource="{Binding Categories}"
ItemTemplate="{StaticResource CategoryDataTemplate}"/>
</Grid>
public class Category
{
public IEnumerable<InnerItem> InnerList
{
get{/*...*/}
}
}
class InnerItem
{
public string Name
{
get{/*...*/}
}
}
public class SampleModel
{
public IEnumerable<Category> Categories
{
get {/*...*/}
}
}
IF you create a new "Windows Phone Pivot Application" the default code shows an example of this but reuses the same items in the listbox in multiple pivotitems.
Here's an overview of what that sample code is doing and how you might go about changing it.
In the constructor of MainPage, the DataContext is set to an object (App.ViewModel).
This Loaded event of MainPage ensures that App.ViewModel is populated.
App.ViewModel is an instance of MainViewModel.
MainViewModel contains an ObservableCollection called "Items". It is this that is bound to an idividual ListBox in a PivotItem:
<controls:PivotItem Header="first">
<ListBox ItemsSource="{Binding Items}">
...
</ListBox>
</controls:PivotItem>
Within the ListBox, you can refer to the contents of the "Items" collection.
If you wanted to adjust this to have different collections for each ListBox/PivotItem you could just adjust this to have multiple collections in the MainViewModel.
HTH.