I have an ItemsControl that contains product categories and I have another ItemsControl that contains a list of all the articles catégoie currently selected, I need to related the current selection of the category with the binding of the ItemsControl articles
<ItemsControl ItemsSource="{Binding Path=Categories}">
...
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Path=CategorieCaption}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
...
</ItemsControl>
<ItemsControl ItemsSource="{Binding Path=SelectedCategories.Articles}">
...
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Path=ArticleCaption}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
...
</ItemsControl>
You just need to update your data bound Article collection each time the Category is changed. If you add a property to data bind with the ListBox.SelectedItem, then you can do that from the property setter:
<ListBox ItemsSource="{Binding Categories}"
SelectedItem="{Binding SelectedCategory}" ... />
..
public Category SelectedCategory
{
get { return selectedCategory; }
set
{
if (selectedCategory != value)
{
selectedCategory = value;
NotifyPropertyChanged("SelectedCategory");
// Selected Category was changed, so update Articles collection
Articles = UpdateArticlesByCategory(selectedCategory);
}
}
}
Related
I'm having a problem while using full XAML code.
To keep it simple, here are the view models I have:
public class MyItemViewModel : INotifyPropertyChanged
{
private int _index;
public int Index
{
get { return _index; }
set { RaisePropertyChanged("Index"); }
}
}
public class MyCollectionViewModel : INotifyPropertyChanged
{
public ObservableCollection<MyItemViewModel> Items { get; }
}
My control is bound to MyCollectionViewModel, and I'm using a CollectionViewSource to synchronize my selected item:
<UserControl x:Class="MyWpfApplication.MyControl">
<!-- The DataContext of the UserControl is MyCollectionViewModel -->
<UserControl.Resources>
<CollectionViewSource x:Key="MyView" Source="{Binding Items}" IsLiveSortingRequested="True">
<CollectionViewSource.LiveSortingProperties>
<s:String>Index</s:String>
</CollectionViewSource.LiveSortingProperties>
<CollectionViewSource.SortDescriptions>
<cm:SortDescription PropertyName="Index" Direction="Ascending" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</UserControl.Resources>
<StackPanel Orientation="Vertical" DataContext="{Binding Source={StaticResource MyView}}">
<ComboBox ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Index, StringFormat={}Item #{0}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<local:MyItemControl DataContext="{Binding /}" />
</StackPanel>
</UserControl>
Here is my problem:
When MyControl is displayed while MyCollectionViewModel.Items contains 1 or more elements, the 1st one is automatically selected and MyItemControl is displayed accordingly. Everything is fine and excpected
But when MyControl is displayed while MyCollectionViewModel.Items contains no items, no item is selected. If one item is added to the list while MyControl is displayed, the selection (i.e. the current item of the CollectionViewSource) does not change.
Is there any way I could achieve this: select the newly added item if there is no selection yet?
I could write some code-behind logic, but I try to avoid that. I also try to avoid creating ICollectionView instances in my view models. Is there any other possibility?
I have a screen with a ListView, with ItemsSource and SelectedItem bound to suitable properties in ViewModel.
This screen is part of a DataTemplate for the screen view model. The problem is: when I "navigate away" from this screen, SelectedItem property in view model is set to null, which is not what I want. Instead, I need the selection to be "remembered" so that when I navigate again to that screen, the last selected item is "still" selected.
If I understand right, the problem is that, when DataTemplate unloads (and so TheView unloads), it deselects the ListView and this is sent to ViewModel via the two-way binding, and I guess I should avoid that somehow.
I tried the following, it works, but feels hackish if not plain wrong:
// in TheSelectedItem setter
if (value == null)
return;
Any suggestion?
Relevant code below:
MainWindow.xaml:
<ContentControl Content="{Binding ActiveScreen}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type vm:TheViewModel}">
<vw:TheView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:OtherViewModel}">
<vw:OtherView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:AnotherViewModel}">
<vw:AnotherView/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
TheView.xaml:
<UserControl.Resources>
<CollectionViewSource
x:Key="TheViewSource"
Source="{Binding TheItems}"
Filter="someFilter"
/>
</UserControl.Resources>
<ListView
ItemsSource="{Binding Source={StaticResource TheViewSource}}"
SelectedItem="{Binding TheSelectedItem, Mode=TwoWay}"
>
TheViewModel.xaml:
public ObservableCollection<ItemViewModel> TheItems { get; set; }
public ItemViewModel TheSelectedItem
{
get { return _tsi; }
set
{
_tsi = value;
RaisePropertyChanged(() => TheSelectedItem);
}
}
ItemViewModel _tsi;
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>
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>
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}}"/>