Align ListView Column Text independently with WPF XAML - c#

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>

Related

How to set Listviewitem margins to use the Listviewitem's background color?

I am using alternating colors, and it works well, but by default I was getting white lines between the items, i.e. margins/padding, so I set them to 0, which makes it look like this:
But I want some margin between them, it's just when I have margin it looks like this:
How can I make it so that the white margins use the background of the listviewitem?
Here is the xaml code:
<Window.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="#1e1e1e"></Setter>
<Setter Property="Foreground" Value="#ffffff"></Setter>
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Margin" Value="0"/>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="#3c3c3c"></Setter>
<Setter Property="Foreground" Value="#ffffff"></Setter>
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Margin" Value="0"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Viewbox Stretch="Uniform">
<ListView Grid.Row="4" Grid.Column="0" Margin="0,0,0,0" ItemsSource="{Binding Coins}" Name="Tasks" Height="250" AlternationCount="2">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="" Width="25" DisplayMemberBinding="{Binding Path=Value.X}">
</GridViewColumn>
<GridViewColumn Header="" Width="25" DisplayMemberBinding="{Binding Path=Value.X}"></GridViewColumn>
<GridViewColumn Header="Symbol" Width="90">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Value.Symbol}" TextAlignment="Center" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Amount" Width="90" DisplayMemberBinding="{Binding Path=Value.X}"></GridViewColumn>
<GridViewColumn Header="Unit Price" Width="90" DisplayMemberBinding="{Binding Path=Value.X}"></GridViewColumn>
<GridViewColumn Header="Capital" Width="90" DisplayMemberBinding="{Binding Path=Value.X}"></GridViewColumn>
<GridViewColumn Header="Profit" Width="90" DisplayMemberBinding="{Binding Path=Value.X}"></GridViewColumn>
<GridViewColumn Header="PNL %" Width="90" DisplayMemberBinding="{Binding Path=Value.X}"></GridViewColumn>
<GridViewColumn Header="Day %" Width="90" DisplayMemberBinding="{Binding Path=Value.X}"></GridViewColumn>
<GridViewColumn Header="Hour %" Width="90" DisplayMemberBinding="{Binding Path=Value.X}"></GridViewColumn>
<GridViewColumn Header="Min %" Width="90" DisplayMemberBinding="{Binding Path=Value.X}"></GridViewColumn>
<GridViewColumn Header="Lowest" Width="90" DisplayMemberBinding="{Binding Path=Value.X}"></GridViewColumn>
<GridViewColumn Header="Price" Width="90">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Value.PriceDecimalDisplay}" TextAlignment="Center" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Highest" Width="90" DisplayMemberBinding="{Binding Path=Value.X}"></GridViewColumn>
<GridViewColumn Header="Vol BTC/h" Width="90" DisplayMemberBinding="{Binding Path=Value.X}"></GridViewColumn>
<GridViewColumn Header="Net BTC/m" Width="90" DisplayMemberBinding="{Binding Path=Value.X}"></GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
</Viewbox>
What about using a Border instead of a Margin for your ListViewItem?
For example you could set your Border inside a ControlTemplate:
<Style x:Key="BorderedItem" TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border Name="Border"
BorderBrush="#1e1e1e"
BorderThickness="0,0,0,10">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then you can set your Style in the ListView:
<ListView ItemContainerStyle="{StaticResource BorderedItem}" />
To change the BorderBrush color depending on your AlternationIndex you could bind it to a property and change it's state from your ViewModel.

Dividing listview into columns, with horizontal scroll (wpf)

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>

WPF default text color of Foreground Color for data binding

How do I get the default color of the text in a WPF control? I'm data-binding the foreground color brush and only want to be able to change color under a certain condition.
A simple example is to color the cell red when the value is 7 for the second column. If I don't know the default color of the text, it is slightly off from the other cells. In the picture below, the default brush is blueish. I use Bushes.Black for the non 7 value.
The C# code for the data binding line is
public Brush brush
{
get
{
if (data2 == 7)
return Brushes.Red;
return Brushes.Black;
}
}
The XAML code is below.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListView Grid.Row="0" Grid.Column="0" Margin="10,20,10,10" ItemsSource="{Binding data}"
Name="DataList">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Width="150" DisplayMemberBinding="{Binding Path=data1}">
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Data1">
<TextBlock>Data 1</TextBlock>
</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Txt2" Text="{Binding data2}" Foreground="{Binding brush}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Data2">
<TextBlock>Data 2</TextBlock>
</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Width="150" DisplayMemberBinding="{Binding Path=data3}">
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Data3">
<TextBlock>Data 3</TextBlock>
</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
</Grid>
only want to be able to change color under a certain condition
Then you should use a trigger in a style applied to the control, so that the property value will be set only under that "certain condition". For example:
<GridViewColumn Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Txt2" Text="{Binding data2}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding data2}" Value="7">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
<TextBlock/>
</DataTemplate>
</GridViewColumn.CellTemplate>
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Data2">
<TextBlock>Data 2</TextBlock>
</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
Alternatively, bind to a property using a converter and return Binding.DoNothing when you don't want to modify the default value. Converters can be useful when dealing with more complicated scenarios. Given the information in your question so far, the above should work fine.

Add lines to gridview

I'm trying add vertical lines to my grid. I have found some examples but nothing works.
<ListView ItemsSource="{Binding Path=CheckableObjectFacilities}" x:Name="ListViewObjectFacilities" Margin="5">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=IsChecked}" Click="cboxObjectFacilities_Click" HorizontalContentAlignment="Stretch"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Name}" Header="Nazwa" >
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Category}" Header="Kategoria" >
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding EnglishName}" Header="EN" ></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Created lines in your GridView by following the example from the following site: Designer WPF.
Here is some XAML I adapted to display system font information:
<Grid>
<Grid.Resources>
<Style x:Key="MyItemContainerStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
</Style>
</Grid.Resources>
<ListView
ItemContainerStyle="{DynamicResource MyItemContainerStyle}"
ItemsSource="{x:Static Fonts.SystemFontFamilies}"
x:Name="myListView"
Width="Auto">
<ListView.View>
<GridView>
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Border BorderBrush="#FF000000" BorderThickness="1,1,0,0" Margin="-6,-2,-6,-2">
<StackPanel Margin="6,2,6,2">
<TextBlock Text="{Binding Source}"/>
</StackPanel>
</Border>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Line Spacing">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Border BorderBrush="#FF000000" BorderThickness="1,1,0,0" Margin="-6,-2,-6,-2">
<StackPanel Margin="6,2,6,2">
<TextBlock Text="{Binding LineSpacing}"/>
</StackPanel>
</Border>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Sample">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Border BorderBrush="#FF000000" BorderThickness="1,1,1,0" Margin="-6,-2,-6,-2">
<StackPanel Margin="6,2,6,2">
<TextBlock FontFamily="{Binding}" FontSize="20"
Text="ABCDEFGabcdefg" />
</StackPanel>
</Border>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>

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