I have a ListView where the View contains a GridView and a number of column definitions.
As Below:
<ListView Name="SampleListView" ItemsSource="{Binding SomeSource}" >
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="{Binding ColumnHeader1,Mode=OneWay}" CellTemplate="{StaticResource Column1Template}" />
<GridViewColumn Header="{Binding ColumnHeader2,Mode=OneWay}" CellTemplate="{StaticResource Column2Template}" />
<GridViewColumn Header="{Binding ColumnHeader3,Mode=OneWay}" CellTemplate="{StaticResource Column3Template}" />
<GridViewColumn Header="{Binding ColumnHeader4,Mode=OneWay}" CellTemplate="{StaticResource Column4Template}" />
<GridViewColumn Header="{Binding ColumnHeader5,Mode=OneWay}" CellTemplate="{StaticResource Column5Template}" />
</GridView>
</ListView.View>
</ListView>
(This works perfectly)
I have a requirement to hide the first column on a user preference so I created a Style Trigger to accomplish this. The code with the style trigger is as below
<ListView Name="SampleListView" ItemsSource="{Binding SomeSource}" >
<ListView.Resources>
<Style x:Key="{x:Type ListView}" TargetType="ListView">
<Style.Triggers>
<DataTrigger Binding="{Binding Source={x:Static p:User.Default},Path=ShowColumn1,Mode=OneWay}" Value="False">
<Setter Property="View">
<Setter.Value>
<GridView x:Name="WithOutColumn1" AllowsColumnReorder="False">
<GridViewColumn Header="{Binding ColumnHeader2,Mode=OneWay}" CellTemplate="{StaticResource Column2Template}" />
<GridViewColumn Header="{Binding ColumnHeader3,Mode=OneWay}" CellTemplate="{StaticResource Column3Template}" />
<GridViewColumn Header="{Binding ColumnHeader4,Mode=OneWay}" CellTemplate="{StaticResource Column4Template}" />
<GridViewColumn Header="{Binding ColumnHeader5,Mode=OneWay}" CellTemplate="{StaticResource Column5Template}" />
</GridView>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Source={x:Static p:User.Default},Path=ShowColumn1,Mode=OneWay}" Value="True">
<Setter Property="View">
<Setter.Value>
<GridView x:Name="WithColumn1" AllowsColumnReorder="False">
<GridViewColumn Header="{Binding ColumnHeader1,Mode=OneWay}" CellTemplate="{StaticResource Column1Template}" />
<GridViewColumn Header="{Binding ColumnHeader2,Mode=OneWay}" CellTemplate="{StaticResource Column2Template}" />
<GridViewColumn Header="{Binding ColumnHeader3,Mode=OneWay}" CellTemplate="{StaticResource Column3Template}" />
<GridViewColumn Header="{Binding ColumnHeader4,Mode=OneWay}" CellTemplate="{StaticResource Column4Template}" />
<GridViewColumn Header="{Binding ColumnHeader5,Mode=OneWay}" CellTemplate="{StaticResource Column5Template}" />
</GridView>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Resources>
</ListView>
When this style is used the Binding for the GridViewColumn Header property does not work.
But the Binding for the CellTemplate does and displays correctly.
The Output Window in VS Shows this Error
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=ColumnHeader1; DataItem=null; target element is 'GridViewColumn' (HashCode=56585823); target property is 'Header' (type 'Object
Can anyone shed some light on why this occurs and how to resolve it?
Things Tried:
Using a RelativePath binding to ensure the DataContext is valid.
(Suspect this doesn't work as i think the GridViewColumn definition
exists outside the visual tree from this post Here)
Creating a DataTemplate for the HeaderTemplate : Same result.
Using an FrameWorkElement as a Proxy as per this post Here
In Case anyone else is having an issue like this i have found a resolution.
The GridViewColumn Header property must be set and bound within XAML tags for that item as below.
<Setter Property="View">
<Setter.Value>
<GridView x:Name="WithOutColumn1" AllowsColumnReorder="False">
<GridViewColumn CellTemplate="{StaticResource Column2Template}">
<GridViewColumnHeader Content="{Binding ColumnHeader2}" />
</GridViewColumn>
<GridViewColumn CellTemplate="{StaticResource Column3Template}">
<GridViewColumnHeader Content="{Binding ColumnHeader3}" />
</GridViewColumn>
<GridViewColumn CellTemplate="{StaticResource Column4Template}">
<GridViewColumnHeader Content="{Binding ColumnHeader3}" />
</GridViewColumn>
<GridViewColumn CellTemplate="{StaticResource Column5Template}">
<GridViewColumnHeader Content="{Binding ColumnHeader3}" />
</GridViewColumn>
</GridView>
</Setter.Value>
Hope fully this will be helpful if you encounter a similar issue.
Related
I have a list view, where I wanted to Hide ContextMenuItems based on some value in the ListView Column. I could achieve this by moving ContextMenu to ListView.ItemContainerStyle. Now my problem is that I am unable to fire Commands on MenuItem. This used to work when ContextMenu was set directly to ListView.
Here is what I have tried and failed. (Used ElementType, ElementName, Direct call etc.).
<UserControl Name="RootElement" DataContext=.Some Context.....>
<ListView ItemsSource="{Binding LicensesView}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Refresh 1" Command="{Binding Path=DataContext.LicenseListRefreshCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
<MenuItem Header="Refresg 2" Command="{Binding Path=DataContext.LicenseListRefreshCommand, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}"/>
<MenuItem Header="Refresh 3" Command="{Binding Path= DataContext.LicenseListRefreshCommand, ElementName=RootElement}" Visibility="{Binding Path=Aktif,Converter= {StaticResource BoolToVisibility}}"/>
<MenuItem Header="Refresh 4" Command="{Binding LicenseListRefreshCommand}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Code" DisplayMemberBinding="{Binding Code}" Width="Auto"/>
<GridViewColumn Header="Active" DisplayMemberBinding="{Binding Active}" Width="150" />
<GridViewColumn Header="Company" DisplayMemberBinding="{Binding Company}" Width="60" />
<GridViewColumn Header="Demo" DisplayMemberBinding="{Binding Demo}" Width="Auto" />
</GridView>
</ListView.View>
</ListView>
</UserControl>
The reason it doesn't work is because Style is a Disconnected property and hence it doesn' respect the visual tree.
I resolved this by using binding Proxy as shown in this answer.
Key is to add DataContext reference as StaticResource.
<UserControl Name="RootElement" DataContext=.Some Context.....>
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisibility" />
<helper:BindingProxy x:Key="Proxy" Data="{Binding}" />
</UserControl.Resources>
<ListView ItemsSource="{Binding LicensesView}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Refresh 1" Command="{Binding Path=Data.LicenseListRefreshCommand, Source={StaticResource Proxy}}" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Code" DisplayMemberBinding="{Binding Code}" Width="Auto"/>
<GridViewColumn Header="Active" DisplayMemberBinding="{Binding Active}" Width="150" />
<GridViewColumn Header="Company" DisplayMemberBinding="{Binding Company}" Width="60" />
<GridViewColumn Header="Demo" DisplayMemberBinding="{Binding Demo}" Width="Auto" />
</GridView>
</ListView.View>
</ListView>
To preface the bulk of the question, I've found several answers regarding CellTemplate and DataTemplate, as well as one setting HeaderContainerStyle, and none of them worked; results ranged from no change to a crash.
I'm trying to change the color of the first entry in each column for my listview (basically so the header for each column sticks out). Here's the most recent thing I've tried with no success. Any suggestions or advice are greatly appreciated.
<ListView Height="380" VerticalAlignment="Top" HorizontalContentAlignment="Stretch">
<ListView.View>
<GridView>
<GridViewColumn Header="First" Width="60" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Txt" Text="{Binding First}" Background="DarkBlue"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Last" Width="60" DisplayMemberBinding="{Binding Last}" />
<GridViewColumn Header="Group" Width="80" DisplayMemberBinding="{Binding Group}" />
</GridView>
</ListView.View>
</ListView>
Is the following code what you are looking for?
For the first row:
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Txt" Text="{Binding First}"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
<Setter TargetName="Txt" Property="Background" Value="DarkBlue"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</GridViewColumn.CellTemplate>
For the header:
<GridViewColumn Header="First" Width="60" >
<GridViewColumn.HeaderContainerStyle>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Background" Value="LightSkyBlue"/>
</Style>
</GridViewColumn.HeaderContainerStyle>
</GridViewColumn>
I want the information in GridViewColumn "from" aligned to the right.
This is what I have done and its not working:
<ListView ItemsSource="{Binding VolumeNumber}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" >
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="SomeStatus" DisplayMemberBinding="{Binding Name}" Width="170" />
<GridViewColumn Header="from" DisplayMemberBinding="{Binding Value, StringFormat=0.000000}" Width="170 >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock TextAlignment="Right" Width="40"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
If you want just one specific column aligned to the right try the example on
https://msdn.microsoft.com/en-us/library/bb961985.aspx
Here's my implementation
<Window.Resources>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</Window.Resources>
<Grid>
<ListView ItemsSource="{Binding VolumeNumber}">
<ListView.View>
<GridView>
<GridViewColumn Header="SomeStatus" DisplayMemberBinding="{Binding Name}" Width="170"/>
<GridViewColumn Header="from" Width="170">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value}" TextAlignment="Right" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
Now DON'T SET DisplayMemberBinding="{Binding Value}" in the GridViewColumn declaration, you need to set it in the textblock Otherwise it will ignore your celltemplate
To change the alignment of the column, you need to specify that the HorizontalContentAlignment property of each ListViewItem is Stretch, so that the elements in each ListViewItem can span or be positioned along the entire width of each column. Because the ListView is bound to a data source, you need to create a style that sets the HorizontalContentAlignment. Next, you need to use a DataTemplate to display the content instead of using the DisplayMemberBinding property. To display the Value of each template, the DataTemplate can just contain a TextBlock that has its HorizontalAlignment property set to Right.
The following example defines the style and DataTemplate necessary to make the column right-aligned, and changes the GridViewColumn to reference the DataTemplate.
The problem here is the ListViewItem (i.e. the container of each GridViewColumn cell).
You have to set its property HorizontalContentAlignment to Stretch.
Have a look here (you also need to remove the DisplayMemberBinding if you want to use a DataTemplate):
<ListView ItemsSource="{Binding VolumeNumber}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="SomeStatus" DisplayMemberBinding="{Binding Name}" Width="170" />
<GridViewColumn Header="from" Width="170">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value, StringFormat=0.000000}" TextAlignment="Right" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Hi all I am new to WPF, I have used a list view to render as grid view. I have a image column for which I set a value by binding the path. Now the problem is I need to change the path of the image based on a condition. If the condition is true I need the path of the image to be different. If false I change it to another path. Can this be done row by row? Below is my listview. Please Help
<ListView Name="LstGrd" Margin="0,105,0,138">
<ListView.View>
<GridView >
<GridViewColumn Header=" Name" Width="120" DisplayMemberBinding="{Binding Path=Name}" />
<GridViewColumn Header=" Address" Width="250" DisplayMemberBinding="{Binding Path=Address}" />
<GridViewColumn Header=" City" Width="50" DisplayMemberBinding="{Binding Path=City}" />
<GridViewColumn Header=" State" Width="75" DisplayMemberBinding="{Binding Path=State}" />
<GridViewColumn Header=" PostalCode" Width="75" DisplayMemberBinding="{Binding Path=PostalCode}" />
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="16" Name="Test" Height="16" Source="{Binding Path=ImagePath,Mode=TwoWay}"/>
<TextBlock Text="Status"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
If I understand your issue properly, you want to change the image if some condition changes. I created a dummy version of the class you are binding to your listview, and added a property called "IsSelected" to show this.
<ListView Name="LstGrd" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListView.View>
<GridView >
<GridViewColumn Header="">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header=" Name" Width="120" DisplayMemberBinding="{Binding Path=Name}" />
<GridViewColumn Header=" Address" Width="250" DisplayMemberBinding="{Binding Path=Address}" />
<GridViewColumn Header=" City" Width="50" DisplayMemberBinding="{Binding Path=City}" />
<GridViewColumn Header=" State" Width="75" DisplayMemberBinding="{Binding Path=State}" />
<GridViewColumn Header=" PostalCode" Width="75" DisplayMemberBinding="{Binding Path=PostalCode}" />
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="16" Name="Test" Height="16" Source="{Binding Path=ImagePath,Mode=TwoWay}"/>
<TextBlock Text="Status"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsChecked}" Value="True">
<Setter Property="Source" Value="{Binding Path=ImagePath2}" TargetName="Test" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
The thing to notice here is that I added a column (this is optional - I just did so to make it easier to demonstrate). Then, in your Image column, you need to add a DataTrigger to your DataTemplate to handle that property change.
Here is just the DataTemplate:
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="16" Name="Test" Height="16" Source="{Binding Path=ImagePath,Mode=TwoWay}"/>
<TextBlock Text="Status"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsChecked}" Value="True">
<Setter Property="Source"
Value="{Binding Path=ImagePath2}"
TargetName="Test" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
This has the advantage over a Converter because it is a XAML only implementation.
You should use a converter:
<Image Source="{Binding Path = ImagePath, Mode = TwoWay, Converter={StaticResource imageToValidatedImageConv}}" />
Where imageToValidatedImageConv is a resource defined as: <local:ImageToValidatedImageConverter x:Key="imageToValidatedImageConv" />
and your converter a class like:
public class ImageToValidatedImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if()
{
//return image1
}
else
{
//return image2
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new Exception("Cant convert back");
}
}
I am having a listview and using view as gridview as follows:
<ListView Grid.Row="1" Grid.Column="0" Height="100" HorizontalAlignment="Left" Margin="10,10,10,10" Name="listView2" VerticalAlignment="Top" Width="300" ItemsSource="{Binding}" SelectionChanged="listView2_SelectionChanged" SelectionMode="Multiple">
<ListView.View>
<GridView AllowsColumnReorder="True">
<GridViewColumn Header="Select">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Path=FirstName}" Header="First Name" Width="100"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=LastName}" Header="Last Name" Width="100"/>
</GridView>
</ListView.View>
</ListView>
Now the issue is that when the user will check on the checkbox the record should get selected. Also is the user selects the record from the list then the corresponding checkboxes should be selected.
How to do it ?
I'm assuming that your view model has IsSelected property:
public Boolean IsSelected
{
get { return isSelected; }
set
{
if (isSelected != value)
{
isSelected = value;
OnPropertyChanged("IsSelected");
}
}
}
private Boolean isSelected;
So, let's change markup:
<ListView ItemsSource="{Binding}" SelectionMode="Multiple">
<!-- add style for the item in list view: -->
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView AllowsColumnReorder="True">
<GridViewColumn Header="Select">
<GridViewColumn.CellTemplate>
<DataTemplate>
<!-- bind the checkbox to the IsSelected property: -->
<CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Name}" Header="Name" Width="100"/>
</GridView>
</ListView.View>
</ListView>
The simplest ways:
<GridViewColumn Header="None">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Width="50"
Height="50"
IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListViewItem}},
Path=IsSelected,Mode=TwoWay}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>