Sunday, January 19, 2014
Award Winning TechNet Guru Article: Binding of DataGrid Column Header
I'm proud to announce that the article Binding of DataGrid Column Header has been awarded with the bronze medal at the TechNet Guru Awards - December 2013 in the section Windows Presentation Foundation (WPF).
Labels:
C#,
Data Binding,
DataBinding,
DataGrid,
DataGrid ColumnHeader,
WPF,
WPF Data Binding,
XAML
Award Winning TechNet Guru Article: Identifying and Resolving Shortcuts/Links of files and folders
I'm proud to announce that the article Identifying and Resolving Shortcuts/Links of Files and Folders has been awarded with the silver medal at the TechNet Guru Awards - December 2013 in the section Visual C#.
Saturday, January 11, 2014
WPF Message Box 2.0.1 Released
Today the final version of WPF Message Box 2.0.1 was released. Support for the .NET 4.5.1 Framework is added to this version. WPF
Message
Box is a simple library. It is using WPF and XAML and is written in C#.
WPF Message Box is a simple and free message box for WPF using MVVM
pattern. Image, buttons, message, and caption can be set. The library is
available for .NET 3.5, .NET 4.0, .NET
4.5, and .NET 4.5.1. For more information, see http://messagebox.codeplex.com/.
Friday, January 10, 2014
WPF About Box 2.0.0 Released
Today the final version of WPF About Box 2.0.0 was released. Support for the .NET Famework 4.5.1 is added to this version. It is now also possible to use only the first 3 digits from the assembly version. WPF About
Box is a simple library. It is using WPF and XAML and is written in C#.
WPF About Box is a simple and free about box for WPF using MVVM
pattern.
Several properties can be set. Some properties are read from assembly,
automatically. The library is available for .NET 3.5, .NET 4.0, .NET
4.5, and .NET 4.5.1. For more information, see http://aboutbox.codeplex.com/.
Monday, December 30, 2013
WPF Binding of DataGrid Column Header in XAML
Dynamically binding to a column header of a DataGrid is not a transparently task. The problem is that the column header is not inheriting from FrameworkElement.
A simple solution to that problem is presented on the Developer Code Samples Gallery (Binding of DataGrid column header) and the TechNet Wiki (Binding of DataGrid Column Header).
There are several solutions for this problem. I will introduce the simplest solution (in my opinion). Since DataGridColumn does not inherit the DataContext of the superior element, you have to indicate the DataContext to use. This can be easily done as the following code snippet shows.
As you can see the header is defined by using a TextBlock. The Text property of the TextBlock is bound to the property HeaderNameText of the DataContext of the DataGrid. In a similar way you could use your own DataContext for the DataGridColumns. By defining the header in this way you could further customize your header by using further elements, e.g. Images. The DataContext of the DataGrid is set in code.
The DataContext is an own object containing the values of the DataGrid and the Header name.
A simple solution to that problem is presented on the Developer Code Samples Gallery (Binding of DataGrid column header) and the TechNet Wiki (Binding of DataGrid Column Header).
There are several solutions for this problem. I will introduce the simplest solution (in my opinion). Since DataGridColumn does not inherit the DataContext of the superior element, you have to indicate the DataContext to use. This can be easily done as the following code snippet shows.
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<TextBlock
Text="{Binding DataContext.HeaderNameText, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
/> </DataGridTemplateColumn.Header>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid>As you can see the header is defined by using a TextBlock. The Text property of the TextBlock is bound to the property HeaderNameText of the DataContext of the DataGrid. In a similar way you could use your own DataContext for the DataGridColumns. By defining the header in this way you could further customize your header by using further elements, e.g. Images. The DataContext of the DataGrid is set in code.
Data data =
new
Data(); data.HeaderNameText =
"Header2";
data.Items =
new
List<string>() {
"Item1",
"Item2" }; DataContext = data;The DataContext is an own object containing the values of the DataGrid and the Header name.
public
class
Data {
public
string
HeaderNameText {
get;
set;
}
public
List<string> Items
{
get;
set;
}
}
Labels:
.NET,
C#,
Data Binding,
DataBinding,
DataGrid,
DataGrid ColumnHeader,
VB.NET,
Visual Basic,
WPF,
WPF Data Binding,
XAML
Saturday, December 28, 2013
Identifying and Resolving Shortcuts/Links of Files and Folders
In Windows file shortcuts can be identified by the file extension. Default
file extension for file and folder shortcuts is ".lnk". But also
".appref-ms" is used as file extension for file shortcuts. Furthermore
could it be possible that installed
applications use the default shortcut file extension for its own
application dependent files. So using file extensions as evidence for
shortcut is not sufficient.
A solution to identify and resolve Windows shortcuts is presented on the Developer Code Samples Gallery (Identifying and Resolving Shortcuts/Links of files and folders) and the TechNet Wiki (Identifying and Resolving Shortcuts/Links of Files and Folders).
A solution to identify and resolve Windows shortcuts is presented on the Developer Code Samples Gallery (Identifying and Resolving Shortcuts/Links of files and folders) and the TechNet Wiki (Identifying and Resolving Shortcuts/Links of Files and Folders).
Thursday, December 26, 2013
Sorting Evolution (3) - Sorting a WPF ListView/GridView by clicking on the header - Sort in ViewModel
Third Generation
After reading Messenger and View Services in MVVM by Laurent Bugnion, I thought about moving sorting again to the ViewModel. The View will still handle the visual elements, while the ViewModel has again the responsibility for sorting. So sorting can also be triggered by the business logic, if needed.
The ViewModel is nearly the same as in the First Generation, but the RelayCommand is not needed.
private ObservableCollection<ResultData> _thirdResultData; private CollectionViewSource _thirdResultDataView; private string _sortColumn; private ListSortDirection _sortDirection; public ObservableCollection<ResultData> ThirdResultData { get { return _thirdResultData; } set { _thirdResultData = value; _thirdResultDataView = new CollectionViewSource(); _thirdResultDataView.Source = _thirdResultData; } } public ListCollectionView ThirdResultDataView { get { return (ListCollectionView)_thirdResultDataView.View; } } public void Sort(string column) { if (_sortColumn == column) { // Toggle sorting direction _sortDirection = _sortDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending; } else { _sortColumn = column; _sortDirection = ListSortDirection.Ascending; } _thirdResultDataView.SortDescriptions.Clear(); _thirdResultDataView.SortDescriptions.Add( new SortDescription(_sortColumn, _sortDirection)); }
The XAML part of the View is the same as in the Second Generation.
<UserControl.Resources> <DataTemplate x:Key="ArrowUp"> <DockPanel> <TextBlock HorizontalAlignment="Center" Text="{Binding}" /> <Path VerticalAlignment="Center" Fill="Black" Data="M 5,5 15,5 10,0 5,5" /> </DockPanel> </DataTemplate> <DataTemplate x:Key="ArrowDown"> <DockPanel> <TextBlock HorizontalAlignment="Center" Text="{Binding}" /> <Path VerticalAlignment="Center" Fill="Black" Data="M 5,0 10,5 15,0 5,0" /> </DockPanel> </DataTemplate> </UserControl.Resources> <Grid> <ListView ItemsSource="{Binding ThirdResultDataView}" GridViewColumnHeader.Click="ThirdResultDataViewClick"> <ListView.View> <GridView> <GridViewColumn DisplayMemberBinding="{Binding ResultNumber}"> <GridViewColumnHeader Content="Number" /> </GridViewColumn> <GridViewColumn DisplayMemberBinding="{Binding ResultOutput}"> <GridViewColumnHeader Content="Output" /> </GridViewColumn> </GridView> </ListView.View> </ListView> </Grid>
The code-behind of the View is nearly the same as in the Second Generation, but the call of the sorting method in the ViewModel is added.
private ListSortDirection _sortDirection; private GridViewColumnHeader _sortColumn; private void ThirdResultDataViewClick(object sender, RoutedEventArgs e) { GridViewColumnHeader column = e.OriginalSource as GridViewColumnHeader; if (column == null) { return; } if (_sortColumn == column) { // Toggle sorting direction _sortDirection = _sortDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending; } else { // Remove arrow from previously sorted header if (_sortColumn != null) { _sortColumn.Column.HeaderTemplate = null; _sortColumn.Column.Width = _sortColumn.ActualWidth - 20; } _sortColumn = column; _sortDirection = ListSortDirection.Ascending; column.Column.Width = column.ActualWidth + 20; } if (_sortDirection == ListSortDirection.Ascending) { column.Column.HeaderTemplate = Resources["ArrowUp"] as DataTemplate; } else { column.Column.HeaderTemplate = Resources["ArrowDown"] as DataTemplate; } string header = string.Empty; // if binding is used and property name doesn't match header content Binding b = _sortColumn.Column.DisplayMemberBinding as Binding; if (b != null) { header = b.Path.Path; } var viewModel = DataContext as SortingViewModel; viewModel.Sort(header); }
The source code can be downloaded from http://code.msdn.microsoft.com/Sorting-a-WPF-ListView-by-ce9cf6d7
Further Posts
- Sorting a WPF ListView/GridView by clicking on the header
- Sort Direction Indicators
- Sort in ViewModel
- Sort Direction Indicators with Adorners
- Reusability
- More Reusability
- Attached Property
- Behaviors (Expression Blend)
Labels:
.NET,
C#,
CollectionViewSource,
GridView,
Header,
ListCollectionView,
ListSortDirection,
ListView,
MVVM,
Sort,
SortDescription,
Sorting,
WPF,
XAML
Monday, December 23, 2013
Sorting Evolution (2) - Sorting a WPF ListView/GridView by clicking on the header - Sort Direction Indicators
Second Generation
After I had implemented sorting (First Generation) of WPF ListView, I wanted to add small glyphs that indicates the sorted column and the sorting direction. In my application sorting is only used if the user triggers it on the view and it changes only the view and not the data. So I decided to move sorting code to code-behind what made it easier to add the small sorting direction arrows to a column header.
First I defined the small glyphs that are used to indicate the sorting direction.
<UserControl.Resources> <DataTemplate x:Key="ArrowUp"> <DockPanel> <TextBlock HorizontalAlignment="Center" Text="{Binding}" /> <Path VerticalAlignment="Center" Fill="Black" Data="M 5,5 15,5 10,0 5,5" /> </DockPanel> </DataTemplate> <DataTemplate x:Key="ArrowDown"> <DockPanel> <TextBlock HorizontalAlignment="Center" Text="{Binding}" /> <Path VerticalAlignment="Center" Fill="Black" Data="M 5,0 10,5 15,0 5,0" /> </DockPanel> </DataTemplate> </UserControl.Resources>
Then I changed the View. I removed the commanding and added a click event handler.
<ListView x:Name="SecondResultData" ItemsSource="{Binding SecondResultData}" GridViewColumnHeader.Click="SecondResultDataViewClick"> <ListView.View> <GridView> <GridViewColumn DisplayMemberBinding="{Binding ResultNumber}"> <GridViewColumnHeader Content="Number" /> </GridViewColumn> <GridViewColumn DisplayMemberBinding="{Binding ResultOutput}"> <GridViewColumnHeader Content="Output" /> </GridViewColumn> </GridView> </ListView.View> </ListView>
The ItemsSource is still binded to a property in the ViewModel.
public ObservableCollection<ResultData> SecondResultData { get; set; }
The click event handler is implemented in code-behind.
private ListSortDirection _sortDirection; private GridViewColumnHeader _sortColumn; private void SecondResultDataViewClick(object sender, RoutedEventArgs e) { GridViewColumnHeader column = e.OriginalSource as GridViewColumnHeader; if (column == null) { return; } if (_sortColumn == column) { // Toggle sorting direction _sortDirection = _sortDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending; } else { // Remove arrow from previously sorted header if (_sortColumn != null) { _sortColumn.Column.HeaderTemplate = null; _sortColumn.Column.Width = _sortColumn.ActualWidth - 20; } _sortColumn = column; _sortDirection = ListSortDirection.Ascending; column.Column.Width = column.ActualWidth + 20; } if (_sortDirection == ListSortDirection.Ascending) { column.Column.HeaderTemplate = Resources["ArrowUp"] as DataTemplate; } else { column.Column.HeaderTemplate = Resources["ArrowDown"] as DataTemplate; } string header = string.Empty; // if binding is used and property name doesn't match header content Binding b = _sortColumn.Column.DisplayMemberBinding as Binding; if (b != null) { header = b.Path.Path; } ICollectionView resultDataView = CollectionViewSource.GetDefaultView( SecondResultData.ItemsSource); resultDataView.SortDescriptions.Clear(); resultDataView.SortDescriptions.Add( new SortDescription(header, _sortDirection)); }
The click event handler set the HeaderTemplate of the columns. Therefore the previously defined glyphs are used. The column that is used to sort gets an arrow that indicates the sorting direction. The arrow is removed from previously sorted column, if necessary.
The source code can be downloaded from http://code.msdn.microsoft.com/Sorting-a-WPF-ListView-by-5769086f
Further Posts
Labels:
.NET,
C#,
CollectionViewSource,
GridView,
Header,
ListCollectionView,
ListSortDirection,
ListView,
MVVM,
Sort,
SortDescription,
Sorting,
WPF,
XAML
Monday, December 16, 2013
Sorting Evolution (1) - Sorting a WPF ListView/GridView by clicking on the header
First Generation
Recently I wanted to sort a WPF ListView using GridView. I was using the MVVM pattern. After some searching and research, I used following XAML code in the View.
<ListView ItemsSource="{Binding FirstResultDataView}"> <ListView.View> <GridView> <GridViewColumn DisplayMemberBinding="{Binding ResultNumber}"> <GridViewColumnHeader Content="Number" Command="{Binding SortCommand}" CommandParameter="ResultNumber" /> </GridViewColumn> <GridViewColumn DisplayMemberBinding="{Binding ResultOutput}"> <GridViewColumnHeader Content="Output" Command="{Binding SortCommand}" CommandParameter="ResultOutput" /> </GridViewColumn> </GridView> </ListView.View> </ListView>
The ItemsSource is binded to the property FirstResultDataView in the ViewModel. The click event of each header is binded to the property SortCommand in the ViewModel by using RelayCommand. The CommandParameter is the property name of an element of the ItemsSource.
The method Sort is connected to the SortCommand in the constructor, so it is called after a header is clicked.
SortCommand = new RelayCommand(Sort);
Following C# code is used in the ViewModel. It displays the property that is binded to the ItemsSource in the View and the Sort method.
private ObservableCollection<ResultData> _firstResultData; private CollectionViewSource _firstResultDataView; private string _sortColumn; private ListSortDirection _sortDirection; public ICommand SortCommand { get; private set; } public ObservableCollection<ResultData> FirstResultData { get { return _firstResultData; } set { _firstResultData = value; _firstResultDataView = new CollectionViewSource(); _firstResultDataView.Source = _firstResultData; } } public ListCollectionView FirstResultDataView { get { return (ListCollectionView)_firstResultDataView.View; } } public void Sort(object parameter) { string column = parameter as string; if (_sortColumn == column) { // Toggle sorting direction _sortDirection = _sortDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending; } else { _sortColumn = column; _sortDirection = ListSortDirection.Ascending; } _firstResultDataView.SortDescriptions.Clear(); _firstResultDataView.SortDescriptions.Add( new SortDescription(_sortColumn, _sortDirection)); }
FirstResultDataView is the items source that is used in the view. It will be created if FirstResultData is set. The type of FirstResultDataView is ListCollectionView which can be used to sort, filter, or group data. It is derived from the View property of CollectionViewSource by setting the source property to FirstResultData.
The Sort method is called after a click on the column header is performed. It is adding a SortDescription to the CollectionViewSource. The SortDescription gets the column that is to sort and direction of sorting by using ListSortDirection.
With that code you get a ListView that can be sorted by clicking on the header. The first click set the sort direction to ascending the second click to descending.
The source code can be downloaded from http://code.msdn.microsoft.com/Sorting-a-WPF-ListView-by-209a7d45
Further Posts
- Sorting a WPF ListView/GridView by clicking on the header
- Sort Direction Indicators
- Sort in ViewModel
- Sort Direction Indicators with Adorners
- Reusability
- More Reusability
- Attached Property
- Behaviors (Expression Blend)
Labels:
.NET,
C#,
CollectionViewSource,
GridView,
Header,
ListCollectionView,
ListSortDirection,
ListView,
MVVM,
Sort,
SortDescription,
Sorting,
WPF,
XAML
Subscribe to:
Posts (Atom)