Dividing listview into columns, with horizontal scroll (wpf) - c#

I have a list view that is divided into two columns. The problem is what happens if the information that comes into the list view is too long of a string.
If I make a fixed width, it will cut some of it. If I make an automatic width, then the initial state of the listview columns will look bad.
Fixed Width:
Automatic Width:
Any ideas what can I do to solve this?
relevant XAML:
<ListView Width="Auto" Height="Auto" Margin="10" Background="#092E3E" Foreground="White" ItemsSource="{Binding BackupEvents}" >
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
...
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridView.ColumnHeaderContainerStyle>
...
</GridView.ColumnHeaderContainerStyle>
<GridView.Columns>
<GridViewColumn Width="200" Header="Time" DisplayMemberBinding="{Binding LVTime}"/>
// auto or fixed?
<GridViewColumn Width="Auto"/"520" Header="Details" DisplayMemberBinding="{Binding LVDetails}"/>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
The best solution I think would be if I could make the column size fixed, but the text/list-entries to wrap into multiple lines if needed. But I'm not sure how to do that...

You can show ellipsis after certain width of data

The best solution I think would be if I could make the column size fixed, but the text/list-entries to wrap into multiple lines if needed. But I'm not sure how to do that...
You could define an implicit TextBlock Style that sets the TextWrapping property of all TextBlocks in the GridView to Wrap:
<ListView Width="Auto" Height="Auto" Margin="10" Background="#092E3E" Foreground="White" ItemsSource="{Binding BackupEvents}" >
<!-- HERE: -->
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="TextBlock.TextWrapping" Value="Wrap" />
</Style>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
...
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridView.ColumnHeaderContainerStyle>
...
</GridView.ColumnHeaderContainerStyle>
<GridView.Columns>
<GridViewColumn Width="200" Header="Time" DisplayMemberBinding="{Binding LVTime}"/>
// auto or fixed?
<GridViewColumn Width="Auto"/"520" Header="Details" DisplayMemberBinding="{Binding LVDetails}"/>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>

Related

Change the text color of a listviewitem in WPF, based on the value of another ListviewItem in the same row

I'd like to change the text color of the "Bedrag" Textblock item to either green or red, based on the value of the first character of the "MarID" listview item in the same row.
When the first character of marID equals 1, the text color should be green, and when it equals 2, the text color should be red.
I've got the following code in my .xaml file:
<ListView x:Name="lstVerrichtingen" HorizontalAlignment="Left" Height="344" Margin="35,28,0,0" VerticalAlignment="Top" Width="934">
<ListView.View>
<GridView>
<GridViewColumn x:Name="gridcolumnVerrichtingID" Header="VerrichtingID" Width="100" DisplayMemberBinding="{Binding VerrichtingID}"/>
<GridViewColumn x:Name="gridcolumnDatum" Header="Datum" Width="100" DisplayMemberBinding="{Binding Datum, StringFormat={}\{0:dd/MM/yyyy\}}"/>
<GridViewColumn x:Name="gridcolumnMarID" Header="MarID" Width="75" DisplayMemberBinding="{Binding MarId}"/>
<GridViewColumn x:Name="gridcolumnBedrag" Header="Bedrag" Width="100" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Bedrag, StringFormat={}{0:0.00}}" TextAlignment="Right" Foreground=""/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn x:Name="gridcolumnVanAan" Header="VanAan" Width="100" DisplayMemberBinding="{Binding VanAan}"/>
<GridViewColumn x:Name="gridcolumnRekeningNummer" Header="Rekeningnummer" Width="100" DisplayMemberBinding="{Binding RekeningNummer}"/>
</GridView>
</ListView.View>
</ListView>
How can I solve this problem? Thank you.
You can check the MarId binding value using a DataTrigger.
Edit:- I noticed now that you want to check the starting char of the MarId. This can be probably done by a Converter. But by creating a property which returns the first char, you can achieve the same.
public char FirstIDChar
{
get
{
return MarID.ToString().First();
}
}
And your xaml:
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding FirstIDChar}" Value="1">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding FirstIDChar}" Value="2">
<Setter Property="Foreground" Value="Green"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>

C# WPF Extending ListView row

I have ListView and I want the last item in the row displayed below the actual row items. Raw copy of xaml:
<ListView x:Name="ListViewRotations" FontFamily="Consolas" MouseDoubleClick="ListViewRotations_MouseDoubleClick">
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove" Click="ContextMenuItemRemoveClicked" />
</ContextMenu>
</ListView.ContextMenu>
<ListView.View>
<GridView>
<GridViewColumn Width="120" Header="Max Craftsmanship" DisplayMemberBinding="{Binding RotationInfo.MaxCraftsmanship}" />
<GridViewColumn Width="120" Header="Min Craftsmanship" DisplayMemberBinding="{Binding RotationInfo.MinCraftsmanship}" />
<GridViewColumn Width="80" Header="Min Control" DisplayMemberBinding="{Binding RotationInfo.MinControl}" />
<GridViewColumn Width="50" Header="CP" DisplayMemberBinding="{Binding RotationInfo.CP}" />
<GridViewColumn Width="130" Header="Score" DisplayMemberBinding="{Binding RotationInfo.Score}" />
<GridViewColumn Width ="Auto" Header="Rotation Time" DisplayMemberBinding="{Binding RotationInfo.RotationTime}" />
<GridViewColumn Width ="Auto" Header="Rotation" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding Images}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="CraftingActionContainer">
<Grid Height="25">
<Image Width="25" Height="25" Source ="{Binding BitmapSource}" VerticalAlignment="Top" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
As you can see, last item is actually a ListBox and since it is quite long I want it to appear on new line.
So far I only thought of creating 2 types of items, one with text data and the other for holding the last item and using template selector. Maybe you know of other ways. Thanks in advance.
Edit:
Images included.
Current result
Wanted result
Generally speaking, is it possible to separate last item from row and modify it so it appears below other items
You can use DataGrid with row details;
<Grid Margin="10">
<DataGrid Name="dgUsers" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Birthday" Binding="{Binding Birthday}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<TextBlock Text="{Binding Details}" Margin="10" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</Grid>
Full tutorial you can find here: Row Details

Align ListView Column Text independently with WPF XAML

I'm learning some WPF controls and am having trouble individually aligning the text in listView columns. I've been able to align them all together, and align the headers, just not the column data itself. I would appreciate some help getting it working.
As a note, this is similar to this question: WPF Listview, align listview item horizontal dynamic not in xaml
I've also tried some other solutions on blogs. While this seems to have been answered, I just can't get it too work. I'd like for the "Filename" column data to be left aligned, and the other two columns center aligned. The headers are fine all centered.
As a side question, what is the preferred method for displaying data like this? The question I referenced alluded to the DataGrid as being easier to work with.
Code:
<ListView x:Name="edtListView" Margin="30,68,30,52" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<EventSetter Event="MouseDoubleClick" Handler="HandleRow_DoubleClick" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridView.ColumnHeaderContainerStyle>
<Style TargetType="{x:Type GridViewColumnHeader}">
<EventSetter Event="Click" Handler="SortHeader_Click"/>
</Style>
</GridView.ColumnHeaderContainerStyle>
<GridViewColumn x:Name="fileNameColumn" DisplayMemberBinding="{Binding Path}" Width="450" TextBlock.TextAlignment="Left" >
<GridViewColumn.Header>
<GridViewColumnHeader Content="Filename" Tag="Path"/>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding MissedEdts}" Width="50" TextBlock.TextAlignment="Center" >
<GridViewColumn.Header>
<GridViewColumnHeader Content="Missed" Tag="MissedEdts"/>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Notes}" Width="95" TextBlock.TextAlignment="Center" >
<GridViewColumn.Header>
<GridViewColumnHeader Content="Notes" Tag="Notes"/>
</GridViewColumn.Header>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
**EDIT: **
Fixed it doing this:
As referenced a couple places, the "DisplayMemberBinding" takes precedence over anything else. I just needed to define a "DataTemplate" for each column and bind the "TextBlock.Text" to the correct "Binding Path". Then delete the "DisplayMemberBinding" references.
<Window.Resources>
<Style TargetType="{x:Type GridViewColumnHeader}">
<EventSetter Event="Click" Handler="SortHeader_Click"/>
</Style>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<EventSetter Event="MouseDoubleClick" Handler="HandleRow_DoubleClick" />
</Style>
<DataTemplate x:Key="value1Template">
<TextBlock TextAlignment="Left" Text="{Binding Path}"/>
</DataTemplate>
<DataTemplate x:Key="value2Template">
<TextBlock TextAlignment="Center" Text="{Binding MissedEdts}"/>
</DataTemplate>
<DataTemplate x:Key="value3Template">
<TextBlock TextAlignment="Center" Text="{Binding Notes}"/>
</DataTemplate>
</Window.Resources>
<ListView x:Name="edtListView" Margin="30,68,30,52" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.View>
<GridView>
<GridViewColumn x:Name="fileNameColumn" CellTemplate="{StaticResource value1Template}" Width="450" >
<GridViewColumn.Header>
<GridViewColumnHeader Content="Filename" Tag="Path"/>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Width="50" CellTemplate="{StaticResource value2Template}">
<GridViewColumn.Header>
<GridViewColumnHeader Content="Missed" Tag="MissedEdts"/>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn CellTemplate="{StaticResource value3Template}" Width="95" >
<GridViewColumn.Header>
<GridViewColumnHeader Content="Notes" Tag="Notes"/>
</GridViewColumn.Header>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Easy, your headers automatically use TextBlock's since you didn't specify the container, specify them in each GridViewColumnHeader and you can do what you want with it (oh and you will need to remove your DisplayMemberBinding since we are explicitly defining the content of the header now), e.g.:
<GridViewColumn x:Name="fileNameColumn" Width="450" TextBlock.TextAlignment="Left" >
<GridViewColumn.Header>
<GridViewColumnHeader Content="Filename" Tag="Path">
<TextBlock Text="{Binding Path}" HorizontalTextAlignment="Right" FontSize="100"/> <!--This line-->
</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>

Datatemplates while using theme does not work - WPF

I am using the theme DarkExpression from WPF Futures.
It does not seem to work well with datatemplates.
Scenario 1:
Here is how it looks like without datatemplates:
Code:
<ListView Name="playlistListView" ItemsSource="{Binding PlaylistList}" Margin="0" SelectionChanged="DatabindedPlaylistListView_SelectionChanged" Background="{x:Null}" Opacity="0.98">
<ListView.View>
<GridView>
<GridViewColumn Width="Auto" DisplayMemberBinding="{Binding Name}">
<GridViewColumnHeader HorizontalContentAlignment="Left" Content="Playlist" Tag="Playlist"/>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Scenario 2:
Here is how it looks like trying to use datatemplates while using the theme:
Code:
<ListView Name="playlistListView" ItemsSource="{Binding PlaylistList}" Margin="0" SelectionChanged="DatabindedPlaylistListView_SelectionChanged" Background="{x:Null}" Opacity="0.98">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<UserControls:SongDataTemplate Margin="4" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Scenario 3:
Here is how it looks like trying to use datatemplates while overriding the theme:
Code:
<UserControl.Resources>
<Style x:Key="ListViewItemStretch" TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Background" Value="Transparent" />
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<ListView Name="playlistListView" ItemContainerStyle="{StaticResource ListViewItemStretch}" ItemsSource="{Binding PlaylistList}" Margin="0" SelectionChanged="DatabindedPlaylistListView_SelectionChanged" Background="{x:Null}" Opacity="0.98">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<UserControls:SongDataTemplate Margin="4" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I want to keep the theme style but I also want to use datatemplates to define how a playlist should look like. Any suggestions?
Note: In scenario 2 and 3 I had to remove
<ListView.View>
<GridView>
<GridViewColumn Width="Auto" DisplayMemberBinding="{Binding Name}">
<GridViewColumnHeader HorizontalContentAlignment="Left" Content="Playlist" Tag="Playlist"/>
</GridViewColumn>
</GridView>
</ListView.View>
Before the datatemplate would be used.
Edit:
The solution given below, works if the type is changed to ListBox and I am using a TextBox instead. I can't however make it work with a ListView.
You are doing it wrong.
When you want to customize ListView you need to work with the View property which is of type ViewBase. Derive a custom View from ViewBase, assign it to ListView.View and you're done.
There's an example in ViewBase Class Documentation
Try by using BasedOn
<Style BasedOn={StaticResource {x:Type ListViewItem}} x:Key="ListViewItemStretch" TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Background" Value="Transparent" />
</Style>
does it work if you substitute
<Grid>
<UserControls:SongDataTemplate Margin="4" />
</Grid>
with a TextBox, for example?
The problem could be generated by your user control..

Update a XAML control template from C#

I have a control template in XAML that contains a listview with a gridview. I want to bind the listview to a datatable created within C# but I can’t see the listview to do this because it is within a control template. I’ve created the equivalent listview in C# by referencing the control template and its contents and thought that I would be able to use this to set the binding but it hasn’t worked. Does any one have any suggestions?
<ControlTemplate x:Key="HistoryView" TargetType="{x:Type ListViewItem}">
<StackPanel x:Name="stkBonusHistory" Height="400" Visibility="Visible">
<GridViewRowPresenter Content="{TemplateBinding Content}" Columns="{TemplateBinding GridView.ColumnCollection}"/>
<!--this is the listview which I am hoping to turn into the "expander" detail-->
<ListView x:Name="lvBonusHistory" Width="950" Visibility="Visible" Height="300">
<ListView.View>
<GridView x:Name="gvBonusHistory" ColumnHeaderTemplate="{StaticResource GridViewHeader}" >
<GridViewColumn Header="Bonus Start" DisplayMemberBinding="{Binding BonusStart}" Width="150"/>
<GridViewColumn Header="Bonus End" DisplayMemberBinding="{Binding BonusEnd}" Width="150"/>
<GridViewColumn Header="Length" DisplayMemberBinding="{Binding Duration}" Width="75"/>
<GridViewColumn Header="Status" DisplayMemberBinding="{Binding BonusStatus}" Width="75"/>
<GridViewColumn Header="Note" DisplayMemberBinding="{Binding Note}" Width="75"/>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</ControlTemplate>
<ListView x:Name="lvBonusList" Width="1000">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template" Value="{StaticResource Default}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding LeaversBonus}" Value="1">
<Setter Property="Template" Value="{StaticResource LeaversBonus}"/>
</DataTrigger>
<DataTrigger Binding="{Binding HistoryShow}" Value="1">
<Setter Property="Template" Value="{StaticResource Default}"/>
<Setter Property="Template" Value="{StaticResource HistoryView}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView x:Name="gvBonusList" ColumnHeaderTemplate="{StaticResource GridViewHeader}" >
<GridViewColumn x:Name="BonusHistory" Width="20" CellTemplate="{StaticResource BonusHistoryGraphic}" >
</GridViewColumn>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding EmployeeName}" Width="250"/>
<GridViewColumn Header="Emp ID" DisplayMemberBinding="{Binding EmpID}" Width="75"/>
<GridViewColumn Header="Employee Start" DisplayMemberBinding="{Binding EmpStart}" Width="150" />
<GridViewColumn Header="Employee End" DisplayMemberBinding="{Binding EmpEnd}" Width="150"/>
<GridViewColumn Header="Bonus Start" DisplayMemberBinding="{Binding BonusStart}" Width="150"/>
<GridViewColumn Header="Bonus End" DisplayMemberBinding="{Binding BonusEnd}" Width="150"/>
<GridViewColumn Header="Length" DisplayMemberBinding="{Binding Duration}" Width="75"/>
</GridView>
</ListView.View>
</ListView>
Codebehind
private void PopulateBonusHistory()
{
// populates dtBonusHistory
BonusHistoryGet();
ControlTemplate HistoryView = (ControlTemplate)stkBonusList.Resources["HistoryView"];
StackPanel stkBonusHistory = (StackPanel)HistoryView.LoadContent();
(stkBonusHistory.Children[1]).Visibility = Visibility.Collapsed;
ListView lvBonusHistory = (ListView)stkBonusHistory.Children[1];
lvBonusHistory.View = (GridView)(lvBonusHistory.FindName("gvBonusHistory"));
Binding bind = new Binding();
lvBonusHistory.DataContext = dtBonusHistory;
lvBonusHistory.SetBinding(ListView.ItemsSourceProperty, bind);
}
try using
lvBonusHistory.Source = dtBonusHistory;
as thats what you are trying to acheive anyway.
Create an attached property on the parent control then use TemplateBinding inside the ControlTemplate. This way you can pass the source into ControlTemplate.

Categories