Does anyone know why I keep getting the "Items collection must be empty before using ItemsSource"-Error?
Here is the code:
<ScrollViewer Margin="8,8,8,8" Grid.Row="3" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
<WrapPanel Orientation="Vertical">
<ItemsControl ItemsSource="{Binding}" x:Name="CustomerList" >>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal">
</WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<View:UserControlCustomerDetails>
</View:UserControlCustomerDetails>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</WrapPanel>
</ScrollViewer>
This is what I do in my Code-Behind:
CustomerList.ItemsSource = _mainViewModel.CustomerCollection;
Note that CustomerCollection is just a simple List<Customers>.
Thanks for your help!
Cheers
Is this code copied verbatim? Do you really have two right angle brackets (>>) at the end of the <ItemsControl... line? If so, the second right angle bracket might be getting treated as text content, which is getting added to the Items collection.
First, remove ItemsSource="{Binding}" from your ItemsControl. This should fix your error i believe.
Secondly, I'm not sure if your WrapPanel is going to work as expected in this case. From my understanding, WrapPanel will do wrapping when it has multiple children that extend out of bounds. In this case, your WrapPanel only has 1 child, an ItemsControl.
Apparently you're using the MVVM pattern. In that case you shouldn't explicitly assign a collection to the ItemsSource property... instead, you should assign a ViewModel to the DataContext of the Window (or UserControl). If your DataContext is _mainViewModel, your binding should be :
<ItemsControl ItemsSource="{Binding CustomerCollection}" ...
Use DataGrid.Items.Clear();
I hope it will be Helpfull...
Related
My Problem is the following:
I have a class which has a ObservableCollection of strings, which gets populated by the selected children.
Those are supposed to be listed in a ListBox.
But the strings aren't listed, rather the object type in FilterList is shown.
<ListBox Grid.Row="2" Grid.Column="0"
ItemsSource="{Binding FilterList}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True"
Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding ListOfActiveFilters}">
<!--<ContentPresenter Content="{Binding ListOfActiveFilters.}"/>-->
<TextBlock Text="{Binding}" />
</HierarchicalDataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Filter List contains the classes which have ListOfActiveFilters as a Property.
I thought that it would work the way I showed it, but it doesn't.
Since that is also the way I saw others do it.
If I were to use a Class with a single string Property as the type of the Collection instead of the Collection of strings I have right now, I think it would work.
I just don't really see the point in creating a class which holds a string property just so that I can bind the ContentPresenter or TextBox to that property.
What am I doing wrong? I am rather new to the topic.
One single ListBox will only be able to display the filters in one single ListOfActiveFilters collection. You could use nested ItemsControls to display them all:
<ItemsControl ItemsSource="{Binding FilterList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding ListOfActiveFilters}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The other option is to modify your data model and put all strings in a single collection. You could then bind the ItemsSource property of the ListBox directly to this one. But a ListBox itself has no concept of hierarhical data.
I have a very simple WPF ListView that I'm using to list blocks of text. I'd like it to scroll vertically, but the text should wrap so that there is no horizontal scroll. All the examples I've seen are overly convoluted DataGridView nesting solutions. This seems like such a simple use-case, however. Here is my current code:
<ListView
Height="Auto"
Width="Auto"
Margin="0"
Name="mLogListView"
FontWeight="Bold"
FontSize="16"
SelectionMode="Single"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Stretch"/>
I've tried setting the ScrollViewer.HorizontalScrollBarVisibility and HorizontalContentAlignment properties but the text simply runs off the end of the control and doesn't wrap.
Each item is added to the ListView.Items collection and is a ListViewItem object. The text is set to the item's Content property.
Here is the code responsible for adding text times to the list:
ListViewItem item = new ListViewItem();
item.Content = "Item text is set here, but refuses to wrap in list view!";
mLogListView.Items.Add(item);
Thank you.
This should be what you need
<ListView Margin="12,23,309,191"
Name="mLogListView"
FontWeight="Bold"
FontSize="16"
SelectionMode="Single"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Stretch" >
<!-- here set the itemTemplate to a TextBlock that can wraps-->
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=.}" TextWrapping="Wrap"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Note the syntax Text="{Binding Path=.}" that is equivalent to Text="{Binding}". This is called empty binding syntax.
In this case Text is bound to the entire ListViewItem object. The empty binding syntax is useful when you want to bind to the entire object item instead of just to single property of the item.
This is convenient for the example because the source object (the ListViewItem) is of type string and you simply want to bind to the string itself.
For more information see msdn at section Specifying the Path to the Value
I wanted to view images in a ListView, it displays by default only one column. To prevent this, you can insert the following code:
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Margin="0" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
Now displays ListView, instead of one column, just one line :-(
To prevent this, you can insert this line of code:
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
So it could look something like this:
<ListView ItemsSource="{Binding YourItemsSource...}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Border ... and so on ...
I hope, it can help someone
;-)
I would like to create a multi-column list of checkboxes, but here's the catch - as I resize the window I would like everything to scale accordingly, including text size. I've been trying to make use of a WrapPanel and ViewBox but can't get the XAML right. Are these controls the best option or should I be using a ListBox (note I don't need selection functionality or scrollbars)? Any suggestions or examples on how I could achieve this would be much appreciated. I'm using MVVM and the list will be data bound, if that makes a difference.
BTW since starting WPF I've been struggling to understand which controls size to their children and which size to their parent. Are there any good sites, cheat sheets, or whatever summarising the behaviour of each control?
If you have a variable number of child elements, you could put a UniformGrid into a ViewBox.
If the child elements have to be visualized by a DataTemplate, you would have to use an ItemsControl with the ItemsPanel property set to such a UniformGrid:
<Viewbox Stretch="Uniform">
<ItemsControl ItemsSource="{Binding Items}" Width="400" Height="200">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="AliceBlue">
<CheckBox Content="{Binding Label}" IsChecked="{Binding IsChecked}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Viewbox>
I am a bit baffled here. I have a List<BitmapImage> in a Viewmodel that is populating. I am trying to display the list on the view with an ItemsControl, but the Images don't show up. Oddly, I can access the same collection and get an image to display if I am using an Image tag.
<ItemsControl ItemsSource="{Binding Path=Images}" MinHeight="80">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" MinWidth="80" MinHeight="80" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Image HorizontalAlignment="Left" Name="image1" Stretch="Uniform" VerticalAlignment="Top" Source="{Binding Path=Images[0]}" MinHeight="80" MaxHeight="200" />
Note that they both point to Images. The Image shows up, the ItemsControl stays empty. What is going on?
You'll solve this by using an ObservableCollection as opposed to a List. The ItemsControl isn't going to rebind on the change notification of a List. You won't have to worry about explicitly calling the change notification for the List either if you use an ObservableCollection.
I was able to replicate your scenario and simply using an ObservableCollection solves the issue. As to why: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
Specifically, see this quote in the Remarks section:
For change notification to occur in a binding between a bound client and a data source, your bound type should either: Implement the INotifyPropertyChanged interface (preferred). Provide a change event for each property of the bound type. Do not do both.
All,
I'm pounding my head against the wall here. What I need is simple, and I'm sure there is a simple answer, but I can't seem to find it.
Situation: I have a Silver light 4.0 app and I'm currently binding a list of strings to an Items control. In the data template for that I have a simple text box that I was doing very basic Binding "{Binding}". I need to update the binding to be twoway so the edits are automatically pushed back to my datacontext.
Here is the Items control before I update the binding:
<ItemsControl x:Name="spLiftHeader" ItemsSource="{Binding Path=WeekLabels}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel x:Name="spLiftHeader" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
**<TextBox x:Name="txtWeekLbl" Text="{Binding}" Foreground="Black" Width="125" TextAlignment="Center"/>**
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Here is the items control after the binding change:
<ItemsControl x:Name="spLiftHeader" ItemsSource="{Binding Path=WeekLabels}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel x:Name="spLiftHeader" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
**<TextBox x:Name="txtWeekLbl" Text="{Binding Mode=TwoWay}" Foreground="Black" Width="125" TextAlignment="Center"/>**
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I've just simply added the "Mode=TwoWay" to the binding.
After updating that, I get the amazingly useless error 4004
"System.Windows.Markup.XamlParseException: Provide value on 'System.Windows.Data.Binding' threw an exception" and the Line/Position reference points right do my updated Binding.
How does one add the Two Way mode to the simple binding?
Thanks in advance.
Nick
Two-way binding to an entire object (a string in this case) makes no sense to Silverlight so it is correct to throw an exception. Shame it is not a more useful error message :)
When there is no Path in the binding the ItemsControl can fetch a value using Object.ToString(), but where will it store the result back? It can't replace the string as that would require placing a new string object back in the collection. Two-way binding is done via reflection against a property of an object.
Instead of a simple list of strings, use a list of some new object that contains a string property and explicitly bind to that property. It will make everything a lot easier. (Make sure your new class and property implement INotifyPropertyChanged).
I am not 100% sure, but I don't think the the Mode=TwoWay should be set in the TextBox itself.
If that doesn't work, try it on both. However, in either case do not use List<T> as a data source behind that items control. Lists do not fire changed event when one of its items has changed. Use ObservableCollection<T> (from the System.Collections.ObjectModel namespace) instead of the List<T>