BindingExpression Path Error - How to structure code in MVVM model? - c#

I have a Button that when clicked should adjust the Widths of two Grids.
<DataTemplate x:Key="ItemTemplate">
<DockPanel Width="Auto">
<Button Click="SelectMovie_Click" DockPanel.Dock="Top">
<Button.Template>
<ControlTemplate >
<Image Source="{Binding image}"/>
</ControlTemplate>
</Button.Template>
<i:Interaction.Behaviors>
<local:UniqueNameBehavior ID="{Binding id}"/>
</i:Interaction.Behaviors>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding ShowRightGridCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<TextBlock Text="{Binding title}" HorizontalAlignment="Center" DockPanel.Dock="Bottom"/>
</DockPanel>
</DataTemplate>
This Button is displayed within a Grid as such:
<Grid Grid.Row="2" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding LeftGridWidth}" />
<ColumnDefinition Width="{Binding RightGridWidth}" />
</Grid.ColumnDefinitions>
// BUTTONS DISPLAYED HERE
<Grid x:Name="LeftGrid" Grid.Row="2" Grid.Column="0" >
<Border BorderThickness="1" BorderBrush="Red">
<ItemsControl ItemTemplate="{StaticResource ItemTemplate}" ItemsSource="{Binding _movies}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="5" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Border>
</Grid>
<Grid x:Name="RightGrid" HorizontalAlignment="Left" Grid.Row="2" Grid.Column="1" >
<DockPanel>
<StackPanel VerticalAlignment="Top" Height="200">
<TextBlock Width="200" Height="50" DockPanel.Dock="Top" HorizontalAlignment="Left">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} ({1})">
<Binding Path = "SelectedMovie.title"/>
<Binding Path = "SelectedMovie.year"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
<StackPanel VerticalAlignment="Top" Height="200">
<Grid HorizontalAlignment="Center">
<Image Source="star_icon.png" Width="100" Height="100" VerticalAlignment="Top"/>
<TextBlock Text="{Binding SelectedMovie.rating}" Style="{StaticResource AnnotationStyle}" Width="150"/>
</Grid>
</StackPanel>
</DockPanel>
</Grid>
</Grid>
ViewModel
public List<MediaDetail> _movies { get; set; }
public string selectedMovieID { get; set; }
private GridLength _leftGridWidth;
private GridLength _rightGridWidth;
private readonly GridLength _defaultRightGridWidth = new GridLength(0, GridUnitType.Pixel);
public MoviePanelViewModel()
{
ShowRightGridCommand = new DelegateCommand(SwitchRightGridWidth);
LeftGridWidth = new GridLength(7, GridUnitType.Star);
RightGridWidth = _defaultRightGridWidth;
}
private void SwitchRightGridWidth()
{
RightGridWidth = RightGridWidth == _defaultRightGridWidth ? new GridLength(3, GridUnitType.Star) : _defaultRightGridWidth;
}
public GridLength LeftGridWidth
{
get { return _leftGridWidth; }
set { _leftGridWidth = value; OnPropertyChanged("LeftGridWidth"); }
}
public GridLength RightGridWidth
{
get { return _rightGridWidth; }
set { _rightGridWidth = value; OnPropertyChanged("RightGridWidth"); }
}
public ICommand ShowRightGridCommand { get; set; }
The problem is that when I run my code, I get the error:
BindingExpression path error: 'ShowRightGridCommand' property not found on 'object' ''MediaDetail'
I am not sure how to structure my code such that the Width properties for the Grids can remain in the ViewModel but the Trigger for my Button also works. The DataContext for my View is the ViewModel.
Is there a good way to achieve this?
Thank you for your help.

The problem is your binding inside a DataTemplate: WPF tries to find the property path ShowRightGridCommand on your MediaDetail class, because the ItemsControl sets the data context for each item container it generates to the corresponding item.
What you actually want to do is binding to the view model. You can do this like so:
{Binding ElementName=LeftGrid, Path=DataContext.ShowRightGridCommand}
LeftGrid is an element outside of the ItemsControl. Its DataContext is your MoviePanelViewModel instance, and there is your ShowRightGridCommand property defined.
A little cleaner would be to put the name root on your view's root control (usually a UserControl or Window), and then use ElementName=root,Path=DataContext.... as your binding - at least that's what I usually do.
An alternative would be to use RelativeSource={RelativeSource UserControl}, but I find ElementName=root to be simpler.

Related

Binding parameter to a nested ListView using SelectedItem

I'm pretty new to coding in c# and I'm trying on a wpf app to transfer data between different folders.
To visualize the folders and subfolders I've got a tabcontrol with different mainfolders, and under each tab a ListView with information on the subfolders.
All data is gathered in a BindingList 'Klinieken', which is filled with objects 'Kliniek' (mainfolders) which contains objects 'Patient' (subfolders) which is filled with information about said folder. Here is the .xaml file for the mainwindow:
<Grid x:Name="LayoutRoot" Background="#555555">
<Grid.RowDefinitions>
<RowDefinition Height="420" />
<RowDefinition Height="116" />
</Grid.RowDefinitions>
<Grid x:Name="KliniekTabs" Background="#555555" Grid.Row="0" Margin="10 10 10 10">
<TabControl ItemsSource="{Binding Klinieken}"
SelectedItem="{Binding BronKliniek}"
TabStripPlacement="Top">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding KliniekNaam}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding Path=Patienten}"
SelectedItem="{Binding Path=SelectedPatient}">
<ListView.Resources>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Left"/>
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn Header="Patientnaam"
Width="250"
DisplayMemberBinding="{Binding PatientNaam}"/>
<GridViewColumn Header="Zisnr"
Width="250"
DisplayMemberBinding="{Binding PatientZis}"/>
<GridViewColumn Header="Aanmaakdatum"
Width="250"
DisplayMemberBinding="{Binding AanmaakDatum}"/>
</GridView>
</ListView.View>
</ListView>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
<Grid x:Name="WindowControls" Background="#777777" Grid.Row="1" Margin="100 5 100 10">
<StackPanel Orientation="Vertical">
<Label Margin="-80 0 0 0" HorizontalAlignment="Center">Doel kliniek</Label>
<ComboBox ItemsSource="{Binding Path=Klinieken}"
x:Name="doelKliniekDD"
SelectedItem="{Binding DoelKliniek}"
Margin="-120 0 0 0"
HorizontalAlignment="Center">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=KliniekNaam}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<StackPanel Orientation="Horizontal" Margin="20 0 0 0" Height="50" VerticalAlignment="Bottom" HorizontalAlignment="Center">
<Button Height="25" Style="{StaticResource Button_Orange}" Command="{Binding TransferButtonCommand}" CommandParameter="{Binding ElementName=window, Mode=OneWay}" Margin="0 0 10 0">Transfer</Button>
<Button Height="25" Style="{StaticResource Button_Orange}" Command="{Binding CopyButtonCommand}" CommandParameter="{Binding ElementName=window, Mode=OneWay}" Margin="10 0 20 0">Kopieer</Button>
<Button Height="25" Style="{StaticResource Button_Grey}" Command="{Binding CloseCommand}" CommandParameter="{Binding ElementName=window, Mode=OneWay}" Margin="20 0 0 0">Cancel</Button>
</StackPanel>
</StackPanel>
</Grid>
</Grid>
And here is the MainViewModel that is referenced in the .xaml:
//attributen
string monacoDirectory;
List<string> aanwezigeClinics;
Installation installation;
//constructor
public MainViewModel()
{
monacoDirectory = ConfigurationManager.AppSettings["monacoDirectory"];
aanwezigeClinics = new List<string>(Directory.GetDirectories(monacoDirectory, "*", SearchOption.TopDirectoryOnly));
aanwezigeClinics.Remove(monacoDirectory + #"\defaults");
aanwezigeClinics.Remove(monacoDirectory + #"\physics");
installation = new Installation(aanwezigeClinics);
Klinieken = new BindingList<Kliniek>();
foreach (var kliniek in installation.Klinieken)
{
Klinieken.Add(kliniek);
}
}
private Kliniek _doelKliniek;
private Kliniek _bronKliniek;
private Patient _selectedPatient;
private BindingList<Kliniek> _klinieken = new BindingList<Kliniek>();
public BindingList<Kliniek> Klinieken
{
get { return _klinieken; }
set { _klinieken = value; }
}
public Kliniek DoelKliniek
{
get { return _doelKliniek; }
set
{
_doelKliniek = value;
OnPropertyChanged();
}
}
public Kliniek BronKliniek
{
get { return _bronKliniek; }
set
{
_bronKliniek = value;
OnPropertyChanged();
}
}
public Patient SelectedPatient
{
get { return _selectedPatient; }
set
{
_selectedPatient = value;
MessageBox.Show("hoi");
OnPropertyChanged();
}
}
The data shows up in the gui just fine, which i was quite happy with. And using SelectedItem on the TabControl and the ComboBox i use later worked out beautifully aswell, but I just cant seem to get the SelectedItem on the ListView to work. I have added a button to test the output of the fields and SelectedPatient always returns as null.
If i check the 'Live Visual Tree' in VS and go to the properties of the ListView i can see the Patient as SelectedItem, so that tells me its not a selection but a binding problem. Furthermore ive tried to google for nested bindings, but the suggestions there didnt change anything about my situation.
Is a nested binding like this possible, or should i take a whole different approach?
Had a similar problem quite a while ago. The suggestions below solved it for me at the time.
Use SelectedValue instead of SelectedItem. This is because SelectedItem doesn't change until the control has been validated. SelectedValue changes whenever the user selects an item. The code you could use is as follows:
SelectedValue="{Binding BronKliniek, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
For the button part, try to provide CommandParameter="{Binding}" instead of CommandParameter="{Binding ElementName=window, Mode=OneWay}". This way, you'll get the value of the current DataContext of the button, which you can then use to extract the data you want from this DataContext.

WPF Command binding in button inside a materialDesign dialog

Im new to WPF and material desing. And im trying to make a dialog for a confirmation of a button, but when i bind the command and press the button it never gets to the method.
The dialog is made in a dynamicly populated listBox.
Window
<ListBox Height="585"
Name="NoteList"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding dtoRecetas}" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<!--VERSION CARTAS-->
<materialDesign:Card Style="{StaticResource cardsRecetas}" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="150"/>
<RowDefinition Height="170"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<!-- DIALOGO DE ELIMINAR RECETA-->
<materialDesign:DialogHost CloseOnClickAway="True" >
<materialDesign:DialogHost.DialogContent>
<StackPanel Margin="16">
<TextBlock>Deseas eliminar esta receta</TextBlock>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Style="{StaticResource MaterialDesignFlatButton}"
IsDefault="True"
Margin="0 8 8 0"
Command="{Binding Path=comandoDeleteReceta}"
CommandParameter="{Binding idReceta}">
Aceptar
</Button>
<Button Style="{StaticResource MaterialDesignFlatButton}"
Margin="0 8 8 0"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
Cancelar
</Button>
</StackPanel>
</StackPanel>
</materialDesign:DialogHost.DialogContent>
<Button x:Name="btnDeleteReceta" Style="{StaticResource btnDeleteReceta}"
Tag="{Binding idReceta}"
Command="{x:Static materialDesign:DialogHost.OpenDialogCommand}">
<materialDesign:PackIcon Kind="RemoveCircle" />
</Button>
</materialDesign:DialogHost>
</StackPanel>
</Grid>
</materialDesign:Card>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ></WrapPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
ViewModel
public class VerRecetasViewModel : BaseViewModel
{
public Command comandoDeleteReceta { get; set; }
public ObservableCollection<DTOReceta> dtoRecetas { get; set; }
public VerRecetasViewModel()
{
RecetasController recController = new RecetasController();
dtoRecetas = new ObservableCollection<DTOReceta>(recController.getAllRecetas());
comandoDeleteReceta = new Command();
comandoDeleteReceta.CanExecuteFunc = obj => true;
comandoDeleteReceta.ExecuteFunc = deleteReceta;
}
public void deleteReceta(object parameter)
{
int idReceta = (int)parameter;
RecetasController recController = new RecetasController();
recController.deleteReceta(idReceta);
}
}
The desired behavior is that when they press "Aceptar" it gets to the "deleteReceta" method, but as right now it looks like is not finding the binded command.
The command class is working and i use commands in other windows this way and it works, i think im losing the context from the dialog or creating it wrong. I tried this way and adding relative source to the binding, but i dont know what the ancestortype should be.
Thanks for the help.
I think it's a problem with the DataContext. So I would set the dataContext of the view like this :
d:DataContext="{d:DesignInstance {x:Type vm:VerRecetasViewModel}}"
and in the ListBox, bind the command on the button like this :
Command="{Binding DataContext.comandoDeleteReceta, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}"
Hope this helps

Treeview contextmenu not working command in HierarchicalDataTemplate

I have a TreeView, which works fine. Within this I have a context menu, which works fine, except for the command which is the issue at hand.
The main parts, I think are here:
<TreeView x:Name="ScenesTreeView01" Grid.Column="0" Width="Auto" Background="AliceBlue" ItemsSource="{Binding Scenes}" SelectedItemChanged="TreeView_SelectedItemChanged" BorderThickness="0">
<TreeView.DataContext>
<viewModels:ScenesViewModel />
</TreeView.DataContext>
<TreeView.Resources>
<LinearGradientBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" StartPoint="0,0" EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#F7D073" Offset="0"/>
<GradientStop Color="#F1A62F" Offset="1"/>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<ContextMenu x:Key="SceneLevel">
<MenuItem Header="Add selected character" Command="{Binding AddSelectedCharacter}"/>
</ContextMenu>
<ContextMenu x:Key="CharacterLevel">
<MenuItem Header="Character Level"/>
</ContextMenu>
</TreeView.Resources>
And here:
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Characters}">
<StackPanel Orientation="Horizontal" ContextMenu="{StaticResource SceneLevel}">
<TextBlock Text="{Binding SceneName}"></TextBlock>
<Image Source="{StaticResource ImgBook1}" Margin="0,0,5,0" Width="32" Height="32"/>
</StackPanel>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<Border BorderThickness="2" BorderBrush="LightBlue" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2" CornerRadius="5,5,5,5">
<StackPanel Orientation="Horizontal" Margin="3" ContextMenu="{StaticResource CharacterLevel}">
<TextBlock FontFamily="Levenim MT" FontSize="16" VerticalAlignment="Center" MinWidth="50" Text="{Binding FirstName}"></TextBlock>
<Image Source="{Binding ImgIcon}" Margin="2" Width="32" Height="32"/>
</StackPanel>
</Border>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
The second one's not really important, but it shows where the two context menus are used. As I said, they appear as expected.
As for my command... I have used commands before in this project and use them at other points in this project. I use MicroMVVM's 'RelayCommand' to create them and they have worked fine so far.
The command in question sits inside the 'ScenesViewModel' class which is, as you might imagine, a view model.
The code for the command is here:
void AddSelectedCharacterExecute()
{
MessageBox.Show("Adding character");
return;
}
bool CanAddSelectedCharacterExecute()
{
return true;
}
public ICommand AddSelectedCharacter { get { return new RelayCommand(AddSelectedCharacterExecute, CanAddSelectedCharacterExecute); } }
It doesn't really do much at the moment, but I can't even get the MessageBox to appear. Break points show that code is not reached when I click on the context menu item.
Have I missed something obvious here? Or is it something in the process? A vague thought is that, because the ViewModel is attached to the TreeView, the TreeView.Resources might not know about it yet? I'm clutching at straws I guess.
Any help would be appreciated.
You should be able to bind to a property of the ScenesViewModel using an {x:Reference}:
<TreeView.Resources>
...
<ContextMenu x:Key="SceneLevel">
<MenuItem Header="Add selected character" Command="{Binding Path=DataContext.AddSelectedCharacter, Source={x:Reference ScenesTreeView01}}"/>
</ContextMenu>
...
</TreeView.Resources>
Forget my comment. My brain was somewhere else.
To do what you want, you have to do some hackish stuff, since a ContextMenu is not part of the VisualTree.
Following you find a small example:
Xaml
<Grid>
<TreeView ItemsSource="{Binding Scenes}" x:Name="rootView">
<TreeView.Resources>
<ContextMenu x:Key="SceneLevel" DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.Tag}">
<MenuItem Header="Add selected character" Command="{Binding AddSelectedCharacter}"/>
</ContextMenu>
<ContextMenu x:Key="CharacterLevel">
<MenuItem Header="Character Level"/>
</ContextMenu>
</TreeView.Resources>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Characters}">
<StackPanel Orientation="Horizontal" ContextMenu="{StaticResource SceneLevel}" Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TreeView}}, Path=DataContext}">
<TextBlock Text="{Binding Name}"></TextBlock>
</StackPanel>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<Border BorderThickness="2" BorderBrush="LightBlue" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2" CornerRadius="5,5,5,5">
<StackPanel Orientation="Horizontal" Margin="3" ContextMenu="{StaticResource CharacterLevel}">
<TextBlock FontFamily="Levenim MT" FontSize="16" VerticalAlignment="Center" MinWidth="50" Text="{Binding Name}"></TextBlock>
</StackPanel>
</Border>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
Code-Behind
public partial class Window2 {
public Window2() {
InitializeComponent();
for (int i = 0; i < 10; i++) {
var s = new Scene() { Name = "Scene " + i };
for (int j = 0; j < 2; j++) {
var c = new Character() { Name = "Character " + j };
s.Characters.Add(c);
}
this.Scenes.Add(s);
}
this.DataContext = this;
}
void AddSelectedCharacterExecute(object param) {
MessageBox.Show("Adding character");
return;
}
public ICommand AddSelectedCharacter {
get {
return new RelayCommand(AddSelectedCharacterExecute, o => true);
}
}
private List<Scene> _scenes = new List<Scene>();
public List<Scene> Scenes => this._scenes;
}
public class Scene {
public Scene() {
this.Characters = new List<Character>();
}
public string Name {
get; set;
}
public List<Character> Characters {
get;
}
}
public class Character {
public string Name {
get; set;
}
}
As you can see, i abuse the Stackpanels Tag as Placeholder for the DataContext. Now i have access in the ContextMenu to the PlacementTarget (which is the StackPanel). After this workaround, the rest should be simple.
Hope this helps! Cheers

Why is Command not invoked when binding value is null?

I have made a grid that I would like to initiate with null or empty values.
But when my textblocks binded value is null the click/tap won't trigger the command.
When I have a value it works fine.
I've also tried to use string.empty and " " which won't work either. Would be happy if somebody could shed some light on this.
XAML
<Grid x:Name="GridPuzzleOuter">
<ItemsControl ItemsSource="{Binding Puzzle.Rows}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Width="270">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0">
<TextBlock Text="{Binding Cells[0].CellValue, Mode=TwoWay}">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Tapped">
<core:InvokeCommandAction
Command="{Binding CellTappedCommand}" CommandParameter="{Binding Cells[0]}"/>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</TextBlock>
</Border>
<Border Grid.Column="1">
<TextBlock Text="{Binding Cells[1].CellValue, Mode=TwoWay}">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Tapped">
<core:InvokeCommandAction
Command="{Binding CellTappedCommand}" CommandParameter="{Binding Cells[1]}"/>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</TextBlock>
</Border>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Rows class
public class Row : ObservableObject
{
public Cell[] Cells { get; set; }
private RelayCommand<Cell> _cellTappedCommand;
public RelayCommand<Cell> CellTappedCommand
{
get
{
return _cellTappedCommand ?? (_cellTappedCommand = new RelayCommand<Cell>((param) => Cellclick(param)));
}
}
private void Cellclick(Cell param)
{
var vm = (new ViewModelLocator()).Main;
vm.SelectedCell = param;
// Do stuff...
}
}
Edit:
Solved by changing XAML into:
<Border Grid.Column="0">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Tapped">
<core:InvokeCommandAction
Command="{Binding CellTappedCommand}" CommandParameter="{Binding Cells[0]}"/>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
<TextBlock Text="{Binding Cells[0].CellValue, Mode=TwoWay}">
</TextBlock>
</Border>
Just move your interaction code to the surrounding Border and be sure to set the Background property to Transparent. Problem solved.
// Best of luck!

Binding ObservableCollection of List

In my Windows Phone application I have a listBox with ContentItems binding :
private ObservableCollection<ContentItemViewModel> _contentItems;
public ObservableCollection<ContentItemViewModel> ContentItems
{
get { return _contentItems; }
}
<ListBox x:Name="ContentListBox" Margin="0,117,12,0" VirtualizingStackPanel.VirtualizationMode="Standard" Logic1:TiltEffect.IsTiltEnabled="True" ItemsSource="{Binding ContentItems}" Tap="ContentListBox_Tap" MinHeight="656" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="vertical" >
<Grid Height="{Binding ItemHeight}" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" x:Name="itemIco1" Width="Auto" Height="Auto" HorizontalAlignment="Left" Source="{Binding IconURL}" Stretch="Fill" CacheMode="BitmapCache" VerticalAlignment="Top" Margin="5,5,5,5" Visibility="Visible"/>
<ListBox IsHitTestVisible="False" Grid.Column="1" VerticalAlignment="Center" >
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<TextBlock x:Name="ContentCategoryTitle" Height="70" Text="{Binding ContentTitle}" Width="460" Margin="5,34,0,0" TextTrimming="WordEllipsis" TextWrapping="NoWrap" FontSize="28" FontFamily="Segoe WP Semibold" Foreground="#FFF7F7F7" VerticalAlignment="Bottom" />
</ListBox>
</Grid>
<Rectangle Fill="#FF585858" Height="1" Margin="0,0,0,0" Width="460" VerticalAlignment="Bottom" HorizontalAlignment="Left" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Is it possible to binding not an ObservableCollection<ContentItemViewModel>, but - ObservableCollection<List<ContentItemViewModel>> ?
Yes that is possible, if you have a collection of collections. Or why not this?
ObservableCollection<ObservableCollection<ContentItemViewModel>>
If you want your UI to be notified of collection changes to your sub collections.
Update
For example:
View Model
public ObservableCollection<ObservableCollection<ContentItemViewModel>> ContentItems
{
get { return _contentItems; }
set { _contentItems = value; // Notify of property change here, this allows you to change the ContentItems reference after view model construction }
}
public MyViewModel()
{
// Populate content items
this.ContentItems = new ObservableCollection
{
new ObservableCollection { new ContentItemViewModel() },
new ObservableCollection { new ContentItemViewModel(), new ContentItemViewModel() }
};
}
View
<ListBox ItemsSource="{Binding ContentItems}" ...>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<ListBox ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding MyContentItemViewModelProperty}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</DataTemplate>
<ListBox.ItemTemplate>
</ListBox>

Categories