I have the following xaml:
<ItemsControl ItemsSource="{Binding ResearchLanguageViewModel.Filters, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Type}"></TextBlock>
<TextBox Text="Search...."></TextBox>
<ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Path=Values}"></CheckBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
With the following objects/collection(s):
public class FilterViewModel
{
public string Type { get; set; }
public ObservableCollection<string> Values { get; set; }
}
public class ResearchLanguageViewModel
{
public int FirmCount { get; set; }
public ObservableCollection<FilterViewModel> Filters { get; set; }
}
I'm trying to bind on the Filters property and the Type property comes out fine. However, I am having trouble getting the Values collection of strings to show as a group of checkboxes. Not sure what I'm doing wrong here...
Values in your View Model is an array, and you are trying (I'm assuming) to create an array of Checkboxes with the values of each checkbox being the index value into that array.
In your model, you are passing in the array of values into the content of one single checkbox control. What you need to do is bind the array to the parent's ItemsSource and bind the new value to the Checkbox control's content. Something like this:
<ItemsControl ItemsSource="{Binding ResearchLanguageViewModel.Filters, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Type}"></TextBlock>
<TextBox Text="Search...."></TextBox>
<ItemsControl>
<ItemsControl.ItemTemplate ItemsSource={Binding Path=Values}>
<DataTemplate>
<CheckBox Content="{Binding Mode=TwoWay}"></CheckBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Bind your item controls, ItemSource property to values.
For a string, you won't even need a template. In your model, you have a collection of strings, so binding to a checkbox template does provide some UI enhancement but my betting is you want the checked status represented in the view model too.
You might want to consider creating an object to encapsulate your label and Checked status and defining your collection based on that.
public class CheckModel
{
public string Label {get; set;}
public bool Checked { get; set; }
}
Then bind your checkbox to:
<CheckBox IsChecked="{Binding Checked}" Content="{Binding Label}" />
I hope this helps.
You will want to bind Values to the ItemsControl not the Checkbox,
<StackPanel>
<TextBlock Text="{Binding Path=Type}"></TextBlock>
<TextBox Text="Search...."></TextBox>
<ItemsControl ItemsSource="{Binding Values}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}"></CheckBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
Related
This is my ListView:
<ListView ItemsSource="{Binding ModuleList}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!--<Image Source="{Binding ModuleImage}" Stretch="UniformToFill"/>-->
<TextBlock Text="{Binding ModuleName}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is the code in WPF (MVVM):
public ItemListViewVM() : base()
{
ModuleList = new List<Module>();
modulLoader.LoadAllModules();
tempModulList = modulLoader.GetAllModules();
foreach (var module in tempModulList)
{
ModuleImage = module.ModuleImage;
ModuleName = module.Name;
ModuleList.Add(module);
}
}
Long story short: The List tempModulList contains Objects of type Module, which has an ImageSource Image and a string Name. Then the ModuleList gets one item after another. When I uncomment the Image in xaml, you can see it. But the TextBlock won't show up no matter what. I checked the string module.Namefor every item, it is not empty.
EDIT: Add Module Class
The Module Class just contains Name and Image:
public class Module
{
public ImageSource ModuleImage { get; set; }
public string Name { get; set; }
}
The Object gets created by deserializing a Json
The Bindings in the ItemTemplate use the properties of the data item class as their source properties. Hence you should write
Text="{Binding Name}"
instead of
Text="{Binding ModuleName}"
Unless you set the View property of a ListView (to e.g. a GridView) you could also better use a ListBox, which is the base class of ListView, and simpler:
<ListBox ItemsSource="{Binding ModuleList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ModuleImage}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Initializing the ModuleList property in the view model constructor would be as simple as this:
public ItemListViewVM()
{
modulLoader.LoadAllModules();
ModuleList = modulLoader.GetAllModules();
}
Alrighty, so I have, as I said, a ComboBox within a ListBox. These are both controls (WPF project using C# in Visual Studio 2010 and MVVM).
I can create them all good and well.
The ListBox contains an ObservableCollection of something called IntWrapper, which just contains and int.
The ComboBox is loaded with an ObservableCollection of something called MissionViewModel, which is just a class that contains a few basic data types.
So the ItemSource for the ListBox and the ComboBox are different.
I can add and items to the ListBox with a button, which just adds a new IntWrapper to the ObservableCollection. Visually this gives me a new ComboBox, which is populated.
What I can't figure out is how to get one of the properties of MissionViewModel to go to the property in the IntWrapper when I select it.
Previously I just used a TextBox in the ListBox, which looked like this:
<ListBox x:Name="lbMissionsToGive" ItemsSource="{Binding MissionsToGive}" SelectedItem="{Binding SelectedMissionToGive}" ContextMenu="{StaticResource RemoveMissionToGiveMenu}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="2" BorderBrush="LightBlue" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2" CornerRadius="5,5,5,5">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="1">Mission ID: </TextBlock>
<TextBox Margin="1" Text="{Binding Int, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My (non working) attempt whereby I replace the TextBox with the ComboBox is this:
<ListBox x:Name="lbMissionsToGive" ItemsSource="{Binding MissionsToGive}" SelectedItem="{Binding SelectedMissionToGive}" ContextMenu="{StaticResource RemoveMissionToGiveMenu}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="2" BorderBrush="LightBlue" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2" CornerRadius="5,5,5,5">
<StackPanel Orientation="Horizontal">
<ComboBox DisplayMemberPath="MissionNameAndID" SelectedValuePath="Int" ItemsSource="{Binding MissionListViewModel.MissionVMs, Source={StaticResource Locator}}"></ComboBox>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I had thought SelectedValuePath would be the thing I wanted, but this so far doesn't seem to work (perhaps I'm using it incorrectly).
Any assistance would be appreciated.
Bind the SelectedValue property of the ComboBox to the Int property of the IntWrapper:
<ComboBox DisplayMemberPath="MissionNameAndID" SelectedValuePath="Int" SelectedValue="{Binding Int}"
ItemsSource="{Binding MissionListViewModel.MissionVMs, Source={StaticResource Locator}}" />
This should work provided that the IntWrapper.Int property has a public setter and that the Int property of the MissionViewModel is of the same type as the Int property of the IntWrapper.
I tried to create a solution for your problem based on your description. To help you more qualified, we would need more information about the MissionViewModel and the Properties contained in it.
I suppose, your Binding does not point to the correct ViewModel. I tried to recreate what you describe below and in my case, the combobox is filled with the Name Property of the MissionVm class.
This is the XAML. Here I changed the ItemsSource Binding to directly point to the ObservableCollection of the DataContext of the parent window.
<ListBox x:Name="lbMissionsToGive" ItemsSource="{Binding MissionsToGive}" SelectedItem="{Binding SelectedMissionToGive}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="2" BorderBrush="LightBlue" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2" CornerRadius="5,5,5,5">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding }"></TextBlock>
<ComboBox Margin="20" Width="50" ItemsSource="{Binding DataContext.MissionVMs, RelativeSource={RelativeSource AncestorType=Window}}" DisplayMemberPath="Name"></ComboBox>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And this is the ViewModel based on your description:
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
var vm1 = new MissionVM { Id = 1, Name = "111"};
var vm2 = new MissionVM { Id = 2, Name = "222" };
var vm3 = new MissionVM { Id = 3, Name = "333" };
MissionVMs = new ObservableCollection<MissionVM> { vm1, vm2, vm3};
MissionsToGive = new ObservableCollection<int> {1, 2, 3};
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public ObservableCollection<int> MissionsToGive { get; set; }
public int SelectedMissionToGive { get; set; }
public ObservableCollection<MissionVM> MissionVMs { get; set; }
}
public class MissionVM
{
public int Id { get; set; }
public string Name { get; set; }
}
This is the Output:
I hope this helps. If i misunderstood you, please give further explanation of the problem.
I have a problem binding all array entries to my ListBox in XAML.
XAML:
<ListBox ItemsSource="{Binding ResultFlag}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding TypeInfo}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
ResultFlag property in my ViewModel (which is the DataContext of the XAML file):
private ObservableCollection<DataField> _resultFlag;
public ObservableCollection<DataField> ResultFlag
{
get { return _resultFlag; }
set
{
_resultFlag = value;
OnPropertyChanged();
}
}
TypeInfo in the DataField class:
public string[] TypeInfo { get; set; }
I would like to show all string entries from above array in the ListBox - how should I do this? I've tried several things including nested Listbox and binding the ItemsSource of the ListBox directly to the array (didn't work, BTW)
Cheers!
What you have in your scenario is a List of List. In order to show that in your list box you need to have nested ListBoxes like this.
<ListBox ItemsSource="{Binding ResultFlag}" >
<ListBox.ItemTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding TypeInfo}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
this is the data template using my ViewModel
<DataTemplate DataType="{x:Type viewModels:MultipleKeysSectionViewModel}" >
<views:TabListItemUserControl Text="{Binding Header}"/>
</DataTemplate>
here is my list of radio buttons
<ListView ItemsSource="{Binding Tabs.Keys}" Grid.Column="1" HorizontalAlignment="Right" Visibility="{Binding IsMultiple, Converter={StaticResource boolToVis}} SelectedItem="{Binding SelectedParameterName}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<RadioButton Content="{Binding}" Margin="0,0,5,0" GroupName="FilterParameters"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListView>
here is my property
private string _selectedParameterName;
public string SelectedParameterName
{
get { return _selectedParameterName; }
set
{
_selectedParameterName = value;
RaisePropertyChanged(() => SelectedParameterName);
}
}
this is my the collection I bind the ListView into
public Dictionary<string, RegisterListViewModel> Tabs { get; set; }
however when I clicked the radio button it doesn't go to Set of the SelectedParameterName property
only when i hit the "box" containing the name of the radio button Set is executed.
Has anyone come across this issue before ?
the IsChecked property of the RadioButton is not bound to anything, therefore clicking on the RadioButton will do nothing.
Change your RadioButton to this:
<RadioButton Content="{Binding}" Margin="0,0,5,0"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}"/>
The Structure
The scenario is that I have a Pivot where each item is the menu of a certain day. Inside that PivotItem I need to display the dishes on the menu, grouped by category (e.g. soups, desserts, ...).
I have implemented this with the MVVM-model.
I thus have the folowing models:
public class Menu{
public string Date;
public List<DishList> Categories;
}
public class DishList
{
public string Category;
public List<Dish> Dishes;
}
public class Dish
{
public string Name;
public string Price;
}
Edit: these are simplified here, the actual structure for each field is like this:
private string _date;
//Get_Set
public string Date
{
get
{
return _date;
}
set
{
if (value != _date)
{
_date = value;
}
}
}
So the structure would be like this: a PivotElement containt a Menu-object. Inside it, I show Categories, a number of DishLists. Inside that Dishlist, I show the Category and the different Dishes, each with it's Name and Price. A mockup to make things a bit more clear (pdf-file on SkyDrive); http://sdrv.ms/12IKlWd
I have the following viewmodel
public class MenuViewModel : INotifyPropertyChanged
{
private ObservableCollection<Menu> _Menus;
}
The view that should implement (the structure) of the desired layout is as following:
<phone:Pivot
ItemsSource="{Binding Menus}">
<phone:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Date}" />
</DataTemplate>
</phone:Pivot.HeaderTemplate>
<phone:Pivot.ItemTemplate>
<DataTemplate>
<ItemsControl
ItemsSource="{Binding Categories}">
<TextBlock
Text="{Binding Category}"/>
<ItemsControl
x:Name="Dishes"
ItemsSource="{Binding Dishes}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="1"
Text="{Binding Name}"/>
<TextBlock
Grid.Column="2"
Text="{Binding Price}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ItemsControl>
</DataTemplate>
</phone:Pivot.ItemTemplate>
</phone:Pivot>
As you can see, there's nested databinding to get to the data it needs.
The only code I then do on the page is
DataContext = App.ViewModel;
The Problem
When I launch it up, I get the correct Data displayed in the PivotItems header, and the correct number of PivotItems. Ufortunately, that's it; the content of the PivotItem stays empty. The first level of databinding thus works, but no further.
The way I was thinking
1st level: each PivotItem is linked to an object of type Menu, with header Menu.Date
2nd level: Inside that PivotItem I set the ItemsSource of a ItemsControl to that Menu.Categories
3rd level : The ItemsSource now is Menu.Categories.Dishes
I have already searched quite a bit and fiddled around with Datacontext and ItemsSource and different kinds of "{Binding ...}", but I can't get it to work. I would like to do the binding in xaml, and not in the code-behind.
Notes
The only function is to display data. The data is stationary and loaded once from a file.
That's why I chose ItemsControl instead of ListBox, there is no need to select anything.
This is a MVVM-approach to my previous question: Databinding + Dynamic Pivot
First off, you're trying to access a private field in the title so that won't work. These also have to be properties, not fields.
<TextBlock Text="{Binding Date}" />
private string Date;
Next you're binding to Category, which is also private and not a property.
<TextBlock Text="{Binding Category}"/>
private string Category;
And you're binding to the Categories field which needs to be a property.
<ItemsControl ItemsSource="{Binding Categories}">
public List<DishList> Categories;
Even if you correct these issues, you still won't get what you want because your outer ItemsControl doesn't have an ItemTemplate.
<ItemsControl ItemsSource="{Binding Categories}">
<TextBlock Text="{Binding Category}"/>
...
</ItemsControl>
Added: Your new error is because the DataTemplate can only have one child element so you need to use a container like a StackPanel.
<ItemsControl ItemsSource="{Binding Categories}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Category}"/>
<ItemsControl x:Name="Dishes" ItemsSource="{Binding Dishes}">
...
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>