I have a databound listbox which is actually displaying two columns of data. It is displayed as follows:
<UserControl.Resources>
<DataTemplate x:Key="AlignedPairs">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Fruits}" Grid.Column="0" />
<TextBlock Text="->" TextAlignment="Center" Grid.Column="1" />
<TextBlock Text="{Binding Colors}" Grid.Column="3" />
</Grid>
</DataTemplate>
</UserControl.Resources>
<ListBox Name="lbStuff" Grid.ColumnSpan="2" Grid.Row="1"
ItemTemplate="{StaticResource AlignedPairs}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Then Itemsource set in codebehind.
Based on some logic however, I would like to set either a line or a item in one of the columns, e.g. a fruit to red, or the line to bold. I have code to work out which Fruit or Color I would like to differentiate (by color/bold) in the code behind, but I can't figure out, especially given the custom listbox display, how I could go about setting a particular item to a different color/bold.
Does anyone have any ideas?
Let me know if any further code is required. Cheers.
edit: all I really want to be able to do is make the problem as easy as possible... loop through each item in the listbox and check with a string, if there is a match SOMEHOW visually distinguish this item in the listbox/listview. There is no need to make this any more complicated than it needs to be. Why you are not able to individually set an items foreground color is beyond me!
edit 2:
It looks like I almost get there with the following (but it throws exception and doesn't work)
foreach (var li in ListView.Items)
{
if (someCriteria == true)
{
((ListViewItem) li).Foreground = Brushes.Red;
//exception throw as this is the actual object stored in this location (the Fruit object for example) not the row or listviewitem I want to change the color of so it can't be cast :(
}
}
This is where the ViewModel design pattern really helps you out.
Presumably you have a class that exposes the properties Fruit and Color. Make a wrapper class that exposes both those properties and also exposes, say, FruitBackgroundBrush and ItemBackgroundBrush. Then you can just bind to those properties in your template, e.g.:
<DataTemplate x:Key="AlignedPairs">
<Grid Background={Binding ItemBackgroundBrush}>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Fruits}"
Background="{Binding FruitBackgroundBrush}"
Grid.Column="0" />
<TextBlock Text="->" TextAlignment="Center" Grid.Column="1" />
<TextBlock Text="{Binding Colors}" Grid.Column="3" />
</Grid>
</DataTemplate>
DataTriggers will take care of this. Here's a good primer: http://en.csharp-online.net/WPF_Styles_and_Control_Templates%E2%80%94Data_Triggers
Related
Is there a way to make sure that the Width="auto" property considers the Width of all elements in a list instead of calculating it individually for every row in the list?
<ListBox x:Name="listBox" HorizontalContentAlignment="Stretch" DockPanel.Dock="Top">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" />
<TextBlock Grid.Column="1" Text="{Binding Value}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I tried this, but as the length of the Name is different for each column, the Width of the Name column of every row is different. Thus the second column starts at a different x position.
You can use SharedSizeGroup property in the ColumnDefinition like this:
<ColumnDefinition SharedSizeGroup="A"/>
Also have a look at this: Grid Size Sharing in WPF.
i have a listbox with a lot of items, and each items when clicked go to a new page, what i want is when i return from the second page, stay at the same position of the item is clicked!
Thats my list!
<ListBox x:Name="list" Loaded="ListView_Loaded" SelectedItem="true" SelectionChanged="searchResultsList_SelectionChanged" ItemsSource="{Binding}" Background="{x:Null}">
<!--<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Margin" Value="0,0,0,15" />
</Style>
</ListView.ItemContainerStyle>-->
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Width="80" Height="80">
<Image Source="{Binding Caminho}" />
</Border>
<StackPanel Margin="0,16,0,0" Grid.Column="2">
<TextBlock Foreground="White" Text="{Binding NomeCurso}" TextWrapping="Wrap" FontSize="{StaticResource TextStyleExtraLargeFontSize}" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
thanks!
If you are using WinRT you can write the following code in your page constructor to cache it, this way the positions will be intact after you go back to this page:
this.NavigationCacheMode = NavigationCacheMode.Required;
And from your sample I cant really see if you are using ListBox or ListView, I will presume ListView which is better as the ListBox is somewhat not needed anymore.
One thing I also noticed is that you use a simple {Binding} for your ItemsSource so maybe it is reset every time you go back because of this (if you are doing something that does this, as this is not visible from your sample code). I always have an additional property of type ObservableCollection and bind to it for example ItemsSource={Binding MyItems}. This way the list is reset only when I reset the property MyItems.
Here's the problem. I have a grid with some data written in xaml:
<ItemsControl x:Name="ItemsControl" ItemsSource="{Binding Path=MyObjectCollection, UpdateSourceTrigger = PropertyChanged}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Width="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="27"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MaxHeight="75" MinHeight="30"></RowDefinition>
</Grid.RowDefinitions>
<Label Name="LabelNumber" Content="{Binding ObjectID}" Grid.Column="0" Style="{StaticResource MyStyleLabel}" />
<control:FocusMeterControl x:Name="HorizontalFocusMeterControl" Value="{Binding ObjectProperty}" Height="Auto" Grid.Column="1" />
<Button Name="RemoveObject" Content="-" Grid.Column="2" Margin="5,0,0,0" Click="ButtonBase_OnClick" Tag="{Binding Point}" Style="{StaticResource MyStyleButton}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
As you can see I'm creating a new grid for each member in my "MyObjectCollection". Ideally I think I should just create one row instead since this would make my next problem - the real problem easier.
However, I have not found any good way to do this in xaml if even possible. Is this possible without populating the collection manually from c# and setting a row-property in my objects manually in order to do something like this
<Label Name="LabelNumber" Grid.Row="{Binding ManuallyCalculatedRowID}" ... />
My primary problem is that I would like the grid/rows to all be equally high and if possible fill out the parent window. If the parent window is way too large MaxHeight should apply and I would just like some empty space below.
The parent control is a Windows Form ElementHost if that makes any difference.
Please let me know if you need any additional info.
To make all rows of equal hight we can use ItemsPanelTemplate and set it to UniformGrid that will take care of equal sizing problem:
<ItemsControl x:Name="ItemsControl" ItemsSource="{Binding Path=MyObjectCollection, UpdateSourceTrigger = PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="1" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Width="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="27"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<Label Name="LabelNumber" Content="{Binding ObjectID}" Grid.Column="0" Style="{StaticResource MyStyleLabel}" />
<control:FocusMeterControl x:Name="HorizontalFocusMeterControl" Value="{Binding ObjectProperty}" Height="Auto" Grid.Column="1" />
<Button Name="RemoveObject" Content="-" Grid.Column="2" Margin="5,0,0,0" Click="ButtonBase_OnClick" Tag="{Binding Point}" Style="{StaticResource MyStyleButton}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Note that I removed row definition in ItemTemplate to lift vertical size restrictions for items. Not sure if that answers your question but that can be good starting point on the road to solution.
I have run into a bizarre problem. I am displaying a UserControl within a UserControl and at the moment each contains a completely identical ListView, as in I copied and pasted it from one to the other. On the parent UserControl, the ListView displays properly, but on the sub-UserControl (whatever it's called), the ListView columns refuse to stretch to fit their content. I have no idea why this is happening since the code of both ListViews is exactly the same. Both are placed directly on the grid.
On the top left is the ListView from the parent control and on the bottom right is that of the child control. Here is the code for both ListViews:
<ListView ItemsSource="{Binding Adventurers}"
Name="AdvListView"
HorizontalAlignment="Stretch"
Grid.Column="2"
Grid.ColumnSpan="1"
Grid.Row="2"
ScrollViewer.CanContentScroll="False"
BorderThickness="3">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<cmd:EventToCommand Command="{Binding ShowAdvWindowCommand}"
CommandParameter="{Binding ElementName=AdvListView, Path=SelectedItem}"
PassEventArgsToCommand="False" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.Resources>
<DataTemplate x:Key="NameTemplate">
<TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding Name}" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" />
</DataTemplate>
<DataTemplate x:Key="StatusTemplate">
<TextBlock Margin="2,1,1,1" Text="{Binding Status}" VerticalAlignment="Center" />
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn Header="Name" CellTemplate="{StaticResource NameTemplate}" />
<GridViewColumn Header="Status" CellTemplate="{StaticResource StatusTemplate}" />
</GridView>
</ListView.View>
</ListView>
Why would this work on one and not the other? I'm really at a loss at this point.
Update: In the parent UserControl, the grid layout is:
<Grid Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
//Listview here among other controls
</Grid>
In the child:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
//Listview here
</Grid>
Modifying Grid.Row, Grid.Column, RowSpan, or ColumnSpan to be correct doesn't fix the problem.
Update: A bit more info that may be relevant: When I try to use Snoop on my program. I get this error:
"BindingFailure was detected - The assembly with display name 'Snoop.XmlSerializers' failed to load in the 'LoadFrom' binding context of the AppDomain with ID 1. The cause of the failure was: System.IO.FileNotFoundException: Could not load file or assembly 'Snoop.XmlSerializers, Version=2.8.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified."
Snoop has no problem with other programs. I don't know if this is related to the issue at all, but I figured I'd post it anyways.
Update: I don't think this would matter, but just to be thorough, here is where the child UserControl is created within the parent:
<Grid>
//Other controls
<UserControl Grid.Column="3"
Grid.Row="3"
Visibility="{Binding AdventurerInfoVisibility}">
<view:AdventurerInfoView />
</UserControl>
</Grid>
At this point I'm completely stumped. I can create a copy of the ListView in the parent UserControl and have it display properly... but for some reason it doesn't want to behave in the child UserControl... I'm open to any ideas and if you need more code I would be more than happy to provide it.
After much tinkering and frustration, I found out what was causing the problem. The child UserControl's Visibility was set to Collapsed by default and was made visible by a button click. When I made it visible by default, the columns stretched properly.
Now I just need to find out how to allow it to start collapsed and still maintain the stretched column width.
I create a deom use your code, and it does not to repeat your problem.
I think maybe your child usercontrol had some TextBlock style, and override your container setting.
Inside my XAML/C# app for Windows 8 Store, I am trying to create a ListView where each ListItem is a horizontal Grid, so I am using the XAML below:
<ListView Name="ResultsView">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="4*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding BestRank}" Grid.Column="0"/>
<TextBlock Text="{Binding PlayerName}" Grid.Column="1"/>
<TextBlock Text="{Binding BestScore}" Grid.Column="2"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
When I run this program, the listview contains all the items from the list it is bound to (through code behind). However in every list-item, contents of all three columns appear together without any space between them. When I create a similar grid outside the listview, it displays fine and takes up entire width of the screen and divides it between the three columns as specified in the XAML above.
What am I doing wrong?
I believe the issue is the ItemContainerStyle needs to have a HorizontalContentAlignment of Stretch. Try this adding this to the ListView:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
Both the ListBox and the Grid should have HorizontalContentAlignment="Stretch"
Specify the width of the grid or add the style as a resource to the grid. Add this right after your </Grid.ColumnDefinitions> line.
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="TextAlignment" Value="Right" />
<Setter Property="Margin" Value="4" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</Grid.Resources>
This will set the properties to all of the TextBlocks in the Grid. You might only need the Margin property. Also consider the properties Width and Padding. You can override this default by setting the property on any given TextBlock to something that isn't the default from the Style.
The default ItemsPanelTemplate is a stack panel as far as I recall meaning that it won't automatically give it's children stretch behavior. You will need to change it, I will edit in a sec just on my mobile waiting for my laptop to boot up :)
Edit:
Er no ignore that I was thinking of ItemsControl, JBrooks is right, just make sure HorizontalContentAlignment is set to Stretch as the default is Left.
<ListView Name="ResultsView" HorizontalContentAlignment="Stretch">
That should work fine - any controls that use XXXXContentAlignment seem to default to Left which I think its a bit inconsistent vs other controls (such as Grid)
actually this is not a problem of Listview. Problem is where you are putting it in? Put your list view in grid. It should work
<ListView Name="ResultsView"
HorizontalContentAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Background="Yellow">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="4*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding BestRank}" Grid.Column="0"/>
<TextBlock Text="{Binding PlayerName}" Grid.Column="1"/>
<TextBlock Text="{Binding BestScore}" Grid.Column="2"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>