GridViewColumnHeader apply sorted style - c#

I have the follwoing listview in my xaml:
<ListView Name="listView1">
<ListView.View>
<GridView>
<GridViewColumn Width="Auto" Header="Name"
DisplayMemberBinding="{Binding nombre}" />
<GridViewColumn Width="200" Header="LastName"
DisplayMemberBinding="{Binding razonSocial}" />
// etc....
I have an ObservableCollection binded to a listview. I created the binding behind code. So any changes that I make to that collection will be reflected on the listview. Also if I want to sort the listview I will just sort the ObservableCollection.
I sort the listview when the user clicks on a gridviewcolumnheader as:
listView1.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler((a, b) =>
{
// check to see what column header was clicked
string bindingProperty =
((Binding)(((GridViewColumnHeader)(b.OriginalSource)).Column.DisplayMemberBinding)).Path.Path;
// using dyniamic linq libraries or the example located at
// http://stackoverflow.com/a/233505/637142
// I will be able to sort my collection of objects by nowing the property name
}));
Anyways I will like to apply a diferent style to the GridViewColumnHeader that was just clicked. I believe there should be already an existing template.
I am looking for something like:
GridViewColumnHeader a = "gridviewColumnHeader that was clicked"
a.Style = "orderByAscGridViewColumnTemplate"

Code Behind:
listView1.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler((a, e) =>
{
GridViewColumnHeader headerClicked =
e.OriginalSource as GridViewColumnHeader;
headerClicked.Column.HeaderTemplate =
Resources["HeaderTemplateArrowUp"] as DataTemplate;
xaml:
<UserControl.Resources>
<DataTemplate x:Key="HeaderTemplateArrowUp">
<DockPanel>
<TextBlock HorizontalAlignment="Center" Text="{Binding}"/>
<Path x:Name="arrow"
StrokeThickness = "1"
Fill = "gray"
Data = "M 5,10 L 15,10 L 10,5 L 5,10"/>
</DockPanel>
</DataTemplate>
</UserControl.Resources>

Related

Add and interact with button in WPF DataGrid

I want to add a button into each row of a DataGrid, which should programmatically be disabled / renamed.
I found out, that it is possible to add a button doing the following:
<DataGrid x:Name="dataGrid_newViews" ItemsSource="{Binding}" AutoGenerateColumns="True" CanUserAddRows="false" Grid.ColumnSpan="2">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="btn_installSnippet" Click="btn_installSnippet_Click">Install</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
When I try to do something like
btn_installSnippet.Content = "abc";
I do get the error message, that the name does not exist in the current context...
Can anybody give me a hint, what I am doing wrong?
The DataTemplate definition in the XAML:
<Window
...
MouseDoubleClick="Window_MouseDoubleClick">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="ButtonTemplate" >
<Button x:Name="btn_installSnippet" Click="btn_installSnippet_Click">Install</Button>
</DataTemplate>
</Grid.Resources>
<DataGrid x:Name="dataGrid_newViews" ItemsSource="{Binding}" AutoGenerateColumns="True" CanUserAddRows="True" Grid.ColumnSpan="2">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Button" CellTemplate="{StaticResource ButtonTemplate}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
Adding a new row in the code behind:
private void Window_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
dataGrid_newViews.Items.Add("a new item");
}
NOTE: The System.Windows.Media.VisualTreeHelper might be used to
iterate all elements in the DataGrid to find out required control.
For maximum control you can do everything in code behind:
DataGridTemplateColumn column = new DataGridTemplateColumn();
column.Header = "NewColumn";
FrameworkElementFactory factory = new FrameworkElementFactory(typeof(Button));
string content = "MyContent";
factory.SetValue(Button.ContentProperty, content);
DataTemplate cellTemplate = new DataTemplate();
cellTemplate.VisualTree = factory;
column.CellTemplate = cellTemplate;
dg1.Columns.Add(column);
You can see more details here: What is the code behind for datagridtemplatecolumn, and how to use it?

How to increase the text size in a gridview

I am dynamically loading a xaml file. This is what the xaml looks like:
<ListView Grid.Row="2" BorderBrush="White"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="ListView1"
ItemsSource="{Binding Path=line}"
HorizontalAlignment="Stretch">
<ListView.View>
<GridView>
<GridViewColumn Header="Lines"
DisplayMemberBinding="{Binding Path=aline}" />
</GridView>
</ListView.View>
</ListView >
The xaml cannot be changed.
You can just change the FontSize in your xaml.
<ListView Grid.Row="2" BorderBrush="White" FontSize="20" .................
However if you are loading your Xaml from a file you will have to load it first then change the FontSize
Example:
using (FileStream stream = new FileStream("c:\\test.xaml", FileMode.Open))
{
var listView = (ListView)XamlReader.Load(stream);
// change font size
listView.FontSize = 20;
// apply listView to whatever you need
}

How do I only show data by filtering the properties in a WPF ListView?

I am working with a WPF control that I created and I am trying to only show certain rows of my list by values of a property. An example is the following, I have a User class that holds a property of Active. How do I tell the .xaml that the list should only show the people that are Active?
Right now I am basically using linq to generate a new list and hand it to the listview based on what I want. However, I would rather just hand the ListView my entire list and let it do the work for me.
Here is my ListView code.
<ListView ItemsSource="{Binding}" DataContext="{Binding }" >
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Index}"/>
<TextBlock Text=". " />
<TextBlock Text="{Binding FirstName}" />
<TextBlock Text="{Binding LastName}" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
You'll need some code behind to add a filter:
See: WPF filtering
ICollectionView view = CollectionViewSource.GetDefaultView(lstMovies.ItemsSource);
view.Filter = null;
view.Filter = new Predicate<object>(FilterMovieItem);
private bool FilterMovieItem(object obj)
{
MovieItem item = obj as MovieItem;
if (item == null) return false;
string textFilter = txtFilter.Text;
if (textFilter.Trim().Length == 0) return true; // the filter is empty - pass all items
// apply the filter
if (item.MovieName.ToLower().Contains(textFilter.ToLower())) return true;
return false;
}

Creating DataTemplate from code behind

Sorry for the not so very general question...
I have a ListView that I have to fill from code behind, and this ListView also need to get its GridViewColumn's from code behind.
For strings it wasn't hard to make the connection, but now I wan't to create a Ellipse that represents a Boolean value in the ListView.
The code in XAML is rather easy, but I fail at converting it to c# code.
Here is parts of the XMAL code:
<ResourceDictionary>
<BooleanToVisibilityConverter x:Key="BoolToVisibility" />
<DataTemplate x:Key="templateAdmin">
<DockPanel>
<Ellipse Width="8" Height="8" Visibility="{Binding Path=isAdmin, Converter={StaticResource BoolToVisibility}}" Fill="Black"/>
</DockPanel>
</DataTemplate>
</ResourceDictionary>
<ListView>
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding LastName}" Header="Last Name"/>
<GridViewColumn CellTemplate="{StaticResource templateAdmin}"
<GridViewColumnHeader">
<TextBlock Text="S"/>
</GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
And by now I have gotten this far:
XAML:
<local:SortableListView >
<ListView.View>
<GridView x:Name="GroupListGridView" />
</ListView.View>
</local:SortableListView>
And in code I have a Collection<GridViewColumn> GridViewColumns that I loop throug and add all items to the GroupListGridView. And I have a function to fill the GridViewColumns collection:
private void CreateGridViews()
{
//Creating the Text was easy!
GridViewColumns.add(new GridViewColumn(){ Header = "LastName", DisplayMemberBinding = new Binding("LastName") });
//Creating the Ellipse was harder!
GridViewColumn gvc = new GridViewColumn();
DataTemplate dt = new DataTemplate();
gvc.DisplayMemberBinding = new Binding("isAdmin");
FrameworkElementFactory fef = new FrameworkElementFactory(typeof(Ellipse));
fef.SetValue(Ellipse.WidthProperty, 8.0D);
fef.SetValue(Ellipse.HeightProperty, 8.0D);
fef.SetValue(Ellipse.FillProperty, new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Black));
//I'm guessing that somewhere here there should be some binding to the visibility property and some sort of conversion done... But I can't figure out how!
dt.VisualTree = fef;
gvc.CellTemplate = dt;
GridViewColumns.Add(gvc);
}
I don't think that I'm that far of... Just that I can't figure out those last steps!
The missing lines are:
var ellipseVisBinding = new Binding("isAdmin");
ellipseVisBinding.Converter = new BooleanToVisibilityConverter();
fef.SetBinding(Ellipse.VisibilityProperty, ellipseVisBinding);
(I note that you've excluded the DockPanel in the template from your code version so I've removed that as well)

How to capture the focus of a TextBox inside a ListView grid

This code generates a Listview with a grid, of multiple name and emails inside TextBox control. I would like to know how can I capture the focus event on one of the TextBox of a row to have the entire ListView row to be selected.
<ListView Name="lstRecipients" ItemsSource="{Binding Path=Recipients}">
<ListView.Resources>
<DataTemplate x:Key="tbNameTemplate">
<TextBox Name="tbName" Text="{Binding Path=Username, ValidatesOnDataErrors=True}"/>
</DataTemplate>
<DataTemplate x:Key="tbEmailTemplate">
<TextBox Name="tbEmail" Text="{Binding Path=Email, ValidatesOnDataErrors=True}"/>
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridView x:Name="gvRecipients">
<GridViewColumn Header="Name" CellTemplate="{StaticResource tbNameTemplate}"/>
<GridViewColumn Header="Email" CellTemplate="{StaticResource tbEmailTemplate}"/>
</GridView>
</ListView.View>
</ListView>
You can add a handler to the GotFocus event on the TextBox that sets the selected item on the ListView. You can use ItemsControl.ContainerFromElement to get the ListViewItem and ItemContainerGenerator.ItemFromContainer to get the bound data object. In XAML:
<TextBox GotFocus="tbName_GotFocus" Name="tbName" Text="{Binding Path=Username, ValidatesOnDataErrors=True}"/>
In code-behind:
private void tbName_GotFocus(object sender, RoutedEventArgs e)
{
var container = lstRecipients.ContainerFromElement((DependencyObject)sender);
if (container != null)
{
lstRecipients.SelectedItem = lstRecipients.ItemContainerGenerator
.ItemFromContainer(container);
}
}
You could also set the handler on the ListView, since GotFocus is a routed event. You could use this to create a handler that could be shared between ListViews. In XAML:
<ListView GotFocus="lstRecipients_GotFocus" Name="lstRecipients" ItemsSource="{Binding Path=Recipients}">
In code-behind:
private void lstRecipients_GotFocus(object sender, RoutedEventArgs e)
{
var selector = sender as Selector;
if (selector != null)
{
var container = selector.ContainerFromElement
((DependencyObject)e.OriginalSource);
if (container != null)
{
selector.SelectedItem = selector.ItemContainerGenerator
.ItemFromContainer(container);
}
}
}
(If you don't want the TextBox to be editable at all, you could also just set Focusable="False" or use a TextBlock instead of a TextBox and focus would go to the ListView and select the row when the cell was clicked.)

Categories