I've got a weird problem where a GridView I have bound to a CollectionViewSource shows the wrong data for the last items. But the actual binding is correct. If I listen for ItemClicked, the DataContext is correct, the UI is just displaying the info for a previous item in the GridView. My goal is to bind to a grouped set of data in a CollectionViewSource, but I've even had it happen if I'm just binding directly to an ObservableCollection.
Here's my XAML:
<Page.Resources>
<CollectionViewSource x:Name="CuratedCVS" IsSourceGrouped="True" />
</Page.Resources>
<SemanticZoom Padding="0">
<SemanticZoom.ZoomedInView>
<GridView x:Name="CuratedFeedsList"
ItemsSource="{Binding Source={StaticResource CuratedCVS}}"
ItemTemplate="{StaticResource CuratedFeedItemTemplate}"
SelectedItem="{Binding SelectedFeed, Mode=TwoWay}"
SelectionMode="Single"
IsSwipeEnabled="True"
IsSynchronizedWithCurrentItem="False"
ShowsScrollingPlaceholders="True"
Padding="20,0">
<GridView.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource CuratedFeedHeaderTemplate}"/>
</GridView.GroupStyle>
</GridView>
</SemanticZoom.ZoomedInView>
<SemanticZoom.ZoomedOutView>
<ListView Background="{Binding SecondaryBackgroundBrush, Source={StaticResource ThemeManager}}"
ItemsSource="{Binding Source={StaticResource CuratedCVS}, Path=CollectionGroups}"
ItemTemplate="{StaticResource CuratedFeedJumpTemplate}"
Padding="0,10">
</ListView>
</SemanticZoom.ZoomedOutView>
</SemanticZoom>
And here's my code to group my data (which seems to work):
var result =
from f in CuratedFeeds
group f by f.Category into g
orderby g.Key
select g;
CuratedCVS.Source = result;
(Where CuratedFeeds is an ObservableCollection)
Has anyone seen this before? This only happens in a Windows 8.1 app. It works flawlessly in a Windows Phone 8.1 app.
So I discovered what the problem was, and unfortunately it didn't have anything to do with the code I posted. I was customizing the ItemContainerStyle, where I used this:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ListViewItemPresenter Content="{Binding}" Margin="0"
SelectedBackground="{Binding SecondaryBackgroundBrush, Source={StaticResource ThemeManager}}"
SelectedForeground="{Binding ForegroundBrush, Source={StaticResource ThemeManager}}"
PlaceholderBackground="{Binding BackgroundBrush, Source={StaticResource ThemeManager}}"
PointerOverBackground="{Binding SecondaryBackgroundBrush, Source={StaticResource ThemeManager}}"
SelectionCheckMarkVisualEnabled="False"
Padding="0,0,0,0"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
In this code, the problem was the Content="{Binding}". I don't know why, but this was screwing up the data. All I had to do was remove the Content="{Binding}" and it worked perfectly.
Related
I have the following problem with my calculator app which I'm doing in the MVVM pattern.
I'm redoing the Windows 10 Calculator in Standard Mode. I made an ObservableCollection of MemoryItem.
MemoryItem is a class that contains an int for the Index, a double for the value and a RelayCommand for the MemoryButtons.
Basically it looks like this and is connected to my ViewModel:
public class MemoryItem
{
public double MemoryItemValue { get; set; }
public int SelectedMemoryItemIndex { get; set; }
public RelayCommand MemoryItemChange { get; set; }
}
So I've binded the SelectedMemoryItemIndex Property to the SelectedItemIndex in WPF.
My ListBox looks like this:
<ListBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Style="{StaticResource MemoryListBoxStyle}"
Visibility="{Binding MemoryVisibility}" ItemsSource="{Binding MemoryCollection}"
SelectedItem="{Binding SelectedMemoryItem}" SelectionMode="Extended" SelectedIndex="{Binding SelectedMemoryItemIndex}"
HorizontalContentAlignment="Right"/>
While the style of it looks like this:
<Style x:Key="MemoryListBoxStyle" TargetType="ListBox">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<UniformGrid Rows="2" Margin="5">
<TextBlock Style="{StaticResource DisplayStyle}" Text="{Binding MemoryItemValue}" FontSize="20"/>
<DockPanel LastChildFill="False">
<Button Content="MC" Style="{StaticResource MemoryItemButton}"
Command="{Binding MemoryItemChange}" CommandParameter="{x:Static md:MemoryUsage.Clear}"/>
<Button Content="M+" Style="{StaticResource MemoryItemButton}"
Command="{Binding MemoryItemChange}" CommandParameter="{x:Static md:MemoryUsage.Add}"/>
<Button Content="M-" Style="{StaticResource MemoryItemButton}"
Command="{Binding MemoryItemChange}" CommandParameter="{x:Static md:MemoryUsage.Substract}"/>
</DockPanel>
</UniformGrid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
The bindings work BUT I don't know how to have the new MemoryItem selected after Inserting the new MemoryItem and deleting the new one. Is there a better of way inserting the new item? ObservableCollection doesn't include a method to update a specific item (as far as I know).
This is the method I'm using to add the value to the MemoryItemValue and insert it in my Collection:
case MemoryUsage.Add:
if (SelectedMemoryItemIndex == -1)
{
SelectedMemoryItemIndex = 0;
}
MemoryItemValue += Eingabe1;
MemoryCollection.Insert(SelectedMemoryItemIndex +1, MItem);
MemoryCollection.RemoveAt(SelectedMemoryItemIndex);
break;
This way it worked but I always have to select the new inserted MemoryItem.
I'm thankful for ANY help provided by you.
Please keep in mind that I'm a beginner in programming and this is my first SO question ever.
Here is a post that helps answer this question.
But basically:
Create an IsSelected property on your MemoryItem class and bind ListBoxItem.IsSelected to that property.
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
</ListBox.ItemContainerStyle>
When you want your new item selected, just set IsSelected to true.
IsSelected = true;
And shazam! It should work.
Here is code copied from another answer that may give you more information.
<ListBox ItemsSource="{Binding Items, Source={StaticResource ViewModel}}"
SelectionMode="Extended">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding IsItemSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ItemText}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Forgive me for leaving that example exactly as I found it.
I have a listView in which I show a collection of Vehicles which are grouped by their MaintenanceState. If the MaintenanceState of the Vehicle updates I expect it to change group. The collection itself is correctly updated, however the view does not update accordingly. Below is some of my code, maybe someone can help me getting this to work.
This is my CollectionViewSource managing my groupings
<CollectionViewSource x:Key="GroupedVehicles" IsLiveGroupingRequested="True" Source="{Binding ItemCollection}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="MaintenanceState" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
Here is my ListView
<ListView ItemContainerStyle="{DynamicResource VehicleItemContainerStyle}"
ItemsSource="{Binding Source={StaticResource GroupedVehicles}}"
SelectedItem="{Binding SelectedItem}"
SelectionMode="Single"
Style="{DynamicResource VehiclesListViewStyle}">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<StackPanel>
<Expander Header="{Binding Path=Name}"
IsExpanded="True"
Style="{DynamicResource VehicleListSectionExpanderStyle}">
<ItemsPresenter />
</Expander>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Number}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is what I do on my ViewModel
Vehicle updatedVehicle = new Vehicle(vehicleNumber, MaintenanceStateEnum.Running);
ItemCollection[index] = updatedVehicle;
The ItemCollection is of type ObservableCollection<Vehicle> and I make sure to only add, remove or replace Vehicles.
The MaintenanceStateEnum has the following values: InMaintenance, MarkedForMaintenance and Running.
This is what my Vehicle looks like
public class Vehicle
{
public Vehicle(int number, MaintenanceStateEnum state) {}
public int Number { get; private set; }
public MaintenanceStateEnum MaintenanceState { get; private set; }
}
So my problem:
If I have Vehicle(3, MaintenanceStateEnum.MarkedForMaintenace) and it is updated to Vehicle(3, MaintenanceStateEnum.InMaintenance) it does not change from the grouping MarkedForMaintenance to the grouping InMaintenance.
Interesting is that it does get removed from the MarkedForMaintenance grouping (the view even leaves a space as if the object is still there).
Does anyone know how I can fix my problem?
I think the issue here is that the view does not know that the collection has changed. You could try to change your container from ItemCollection to ObservableCollection which implements both INotifyCollectionChanged and INotifyPropertyChanged.
I am working on some XAML where I have a RibbonComboBox:
<RibbonComboBox SelectionBoxWidth="150" Grid.Row="0">
<RibbonGallery SelectedItem="{Binding SelectedUtilityRun, Mode=TwoWay}">
<RibbonGalleryCategory ItemsSource="{Binding UtilityRunLabels}" />
</RibbonGallery>
</RibbonComboBox>
When it displays, it shows the items horizontally rather than vertically as I expected:
How do I style it to place the items vertically?
Try setting RibbonGallery.MaxColumnCount to 1:
<RibbonGallery ... MaxColumnCount="1">
Set ItemsPanel in Style and Set Orientation=Vertical
<Style TargetType="RibbonComboBox">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"
VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</ItemsPanelTemplate>
</Setter.Value>
I hope this will help.
I'm creating a ListBox in my C# code, and I need to write this code in C#, although I'm not exactly sure how to do it,
http://smehrozalam.wordpress.com/2011/01/31/silverlight-and-wpf-how-to-make-items-stretch-horizontally-in-a-listbox/
<Grid>
<Grid.Resources>
<Style x:Key="ListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</Grid.Resources>
<ListBox Margin="100" ItemsSource="{Binding MyList}"
ItemContainerStyle="{StaticResource ListBoxItemStyle}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding}"
Background="LightYellow"
TextWrapping="Wrap" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
More specificly, how do I write this in C#
<Style x:Key="ListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
And
ItemContainerStyle="{StaticResource ListBoxItemStyle}"
You can create the style via:
Style style = new Style(typeof(ListBoxItem));
style.Setters.Add(new Setter(Control.HorizontalContentAlignment, HorizontalAlignment.Stretch));
You can then set this via:
listBox.ItemContainerStyle = style;
The answer posted by Reed Copsey will work.
A naive alternative (though honestly likely more "efficient," since it's explicit) is to set the HorizontalContentAlignment property of your ListBoxItem objects to HorizontalAlignment.Stretch, when you construct them (if you're also constructing them in code).
ListBoxItem i = new ListBoxItem { HorizontalContentAlignment = HorizontalAlignment.Stretch };
I am hoping that this is something simple and have just missed something obvious. I am using MVVM and have a Datagrid which is bound to a CollectionViewSource this in turn is populated with an ObservableCollection, the ObservableCollection is initally unpopulated and added to by way of tick boxes on the UI
The problem I have is that when the ObservableCollection is added to, the Headers appear for the grouping on the DataGrid but the individual rows themselves don't.
Any help really appreciated,
Here is my XAML for the Datagrid
<DataGrid DataContext="{Binding GroupedBookings}"
ItemsSource="{Binding SourceCollection}"
AutoGenerateColumns="False"
SelectionMode="Single"
SelectionUnit="FullRow"
CanUserSortColumns="True"
SelectedItem="{Binding SelectedBooking}"
CanUserAddRows="False">
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=MemberCount.SupporterType}"
FontWeight="Bold"
Padding="3" />
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander>
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=ItemCount}"
Margin="8 0 4 0" />
</StackPanel>
</Expander.Header>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Cost"
Binding="{Binding Cost}" />
<DataGridTextColumn Header="Order No"
Binding="{Binding LinkedOrderID}" />
</DataGrid.Columns>
</DataGrid>
And my code for the Collections
_bookings = new ObservableCollection<Booking>(rep.Bookings_Get().Where(x => x.JobID == CurrentJob.JobID));
GroupedBookings = CollectionViewSource.GetDefaultView(Bookings);
GroupedBookings.GroupDescriptions.Add(new PropertyGroupDescription("MemberCount.SupporterType"));
To confirm the observable collection is updating fine as is the CollectionView in the VM, the ItemCount in the header even increases in the UI I just can't seem to make the rows appear.
Thanks in advance
Edit:
I have changed my code to assign directly to Bookings as opposed to _bookings as per EthicalLogics suggestion but this hasn't helped Bookings is defined as below:
public ObservableCollection<Booking> Bookings
{
get { return _bookings; }
set
{
_bookings = value;
OnPropertyChanged("Bookings");
}
}
Here is GroupedBookings
public ICollectionView GroupedBookings
{
get { return _groupedBookings; }
set
{
_groupedBookings = value;
OnPropertyChanged("GroupedBookings");
}
}
I added the following to my XAML, turns out I had missed something small however having looked at multiple examples of using a CollectionViewSource and grouping in a data grid I only found the microsoft one to contain this as part of the GroupStyle
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
Hope this helps anyone that has a similar issue
public ObservableCollection<Booking> _bookings{get;set;}
Binding Source must be a property not field. Because binding system uses reflection and it looks only for properties not fields.I hope this will help.