Expand Header binding don't show the value properly (WPF/C#) - c#

I'm using data binding to show some data in a listview. I'm using headers to sumarize my data and I want to show a text extracted from my itemsource but doesn't worked. There is some mistake in this portion of code? How can I provide the correct datasource to my wpf?
In Main.xml I fill my list with StructLog.cs class, and on wpf I show the data from each item of the list. The others values work normally, and the header are created, just the text on header expander don't appear.
Main.xml
List<StructLog> all = new List<StructLog>();
foreach (ObservableCollection<StructLog> res in Patterns.Results)
{
foreach (StructLog r in res)
{
all.Add(r);
}
}
lstResults.ItemsSource = all;
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(all);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("Pattern");
view.GroupDescriptions.Add(groupDescription);
StructLog.cs
public class StructLog
{
public int LineNumber{ get; set;}
public string LineLog{ get; set;}
public DateTime Time{ get; set;}
public string Source{ get; set;}
public string Type{ get; set;}
public string Pattern{ get; set;}
public StructLog(StructLine s,string patternName)
{
this.LineNumber = s.LineNumber;
this.LineLog = s.LineLog;
this.Time = s.Time;
this.Source = s.Source;
this.Type = s.Type;
this.Pattern = patternName;
}
}
Window.xaml
<ListView Name="lstResults" Grid.Row="1" IsEnabled="True" Grid.RowSpan="4" DataContext="Results" Grid.ColumnSpan="5" Margin="5,5">
<ListView.View>
<GridView>
<GridViewColumn Header="Linha" Width="Auto" DisplayMemberBinding="{Binding LineNumber}" />
<GridViewColumn Header="Fonte" Width="Auto" DisplayMemberBinding="{Binding Source}" />
<GridViewColumn Header="Data" Width="Auto" DisplayMemberBinding="{Binding Time}" />
<GridViewColumn Header="Log" Width="Auto" DisplayMemberBinding="{Binding LineLog}" />
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="True">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Teste:" FontWeight="Bold" Foreground="Gray" FontSize="22" VerticalAlignment="Bottom" />
<TextBlock Text="{Binding Pattern}" FontWeight="Bold" Foreground="Gray" FontSize="22" VerticalAlignment="Bottom" />
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>

In order to display a value in the group header, grouped items will in the Items property of the GroupItem class. So you can do binding like Text ="{Binding Items[0].Pattern }". This will bind the value of the first item in the group, since all the values in the group will be similar as the values are grouped by Pattern property.
Try this.
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="True">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Teste:" FontWeight="Bold" Foreground="Gray" FontSize="22" VerticalAlignment="Bottom" />
<TextBlock Text="{Binding Items[0].Pattern}" FontWeight="Bold" Foreground="Gray" FontSize="22" VerticalAlignment="Bottom" />
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>

Related

WPF ListView inside Grouped TreeView not working

In a WPF Project I have a set of record objects with the properties School, Subject, FirstName and LastName. The records are grouped by School and Subject using CollectionViewSource in XAML and this is used by a TreeView to show the grouped items. The groupings work fine.
The problem is I would like to show the FirstName and LastName of the records under the Subject in a ListView using a GridView as its View with FirstName and LastName as columns, but I can't figure out how to do this.
Here is an image of the current display:
Here's some sample code to show what I mean.
public class Record
{
public string School { get; set; }
public string Subject { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var records = new Record[]
{
new Record() { School = "School A", Subject = "Maths" , FirstName = "Fred" , LastName = "Blogs"},
new Record() { School = "School A", Subject = "English" , FirstName = "Alice" , LastName = "Lane"},
new Record() { School = "School B", Subject = "Geography" , FirstName = "John" , LastName = "Smith"},
new Record() { School = "School B", Subject = "Geography" , FirstName = "Burt" , LastName = "Lancaster"},
new Record() { School = "School C", Subject = "Chemistry" , FirstName = "Dee" , LastName = "Kaye"}
};
this.DataContext = records;
}
}
XAML :
<Window x:Class="ListViewInTreeView.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ListViewInTreeView"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<CollectionViewSource x:Key="listings"
Source="{Binding .}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="School" />
<PropertyGroupDescription PropertyName="Subject" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
<Grid>
<TreeView Grid.Row="4" DataContext="{StaticResource listings}" ItemsSource="{Binding}" >
<TreeView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander Margin="0,0,0,0" IsExpanded="True" BorderBrush="#FFA4B97F"
BorderThickness="0,0,0,1">
<Expander.Header>
<DockPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}"/>
<TextBlock Text=" : "/>
<TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount}"/>
<TextBlock Text=" items(s)"/>
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter Margin="20,0,0,0" />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</TreeView.GroupStyle>
<TreeView.Resources>
<!-- NEED HELP HERE I THINK ?-->
<HierarchicalDataTemplate DataType="{x:Type GroupItem}">
<ListView ItemsSource="{Binding .}">
<ListView.View>
<GridView>
<GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}"/>
<GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}"/>
</GridView>
</ListView.View>
</ListView>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>
</Window>
Use 2 GroupStyles, one for the School group and another one for the Subject group:
<TreeView Grid.Row="4" DataContext="{StaticResource listings}" ItemsSource="{Binding}" >
<TreeView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander Margin="0,0,0,0" IsExpanded="True" BorderBrush="#FFA4B97F" BorderThickness="0,0,0,1">
<Expander.Header>
<DockPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}"/>
<TextBlock Text=" : "/>
<TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount}"/>
<TextBlock Text=" items(s)"/>
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter Margin="20,0,0,0" />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander Margin="0,0,0,0" IsExpanded="True" BorderBrush="#FFA4B97F" BorderThickness="0,0,0,1">
<Expander.Header>
<DockPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}"/>
<TextBlock Text=" : "/>
<TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount}"/>
<TextBlock Text=" items(s)"/>
</DockPanel>
</Expander.Header>
<Expander.Content>
<ListView ItemsSource="{Binding Items}">
<ListView.View>
<GridView>
<GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}"/>
<GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}"/>
</GridView>
</ListView.View>
</ListView>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</TreeView.GroupStyle>
</TreeView>
You probably also want to move the common property settings for the Expander and GroupItem to two styles that are used by both GroupStyles:
<TreeView Grid.Row="4" DataContext="{StaticResource listings}" ItemsSource="{Binding}" >
<TreeView.Resources>
<Style TargetType="GroupItem">
<Setter Property="Margin" Value="0,0,0,5"/>
</Style>
<Style TargetType="Expander">
<Setter Property="Margin" Value="0,0,0,0" />
<Setter Property="IsExpanded" Value="True" />
<Setter Property="BorderBrush" Value="#FFA4B97F" />
<Setter Property="BorderThickness" Value="0,0,0,1" />
<Setter Property="Header" Value="{Binding}" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<DockPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}"/>
<TextBlock Text=" : "/>
<TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount}"/>
<TextBlock Text=" items(s)"/>
</DockPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
<TreeView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander>
<Expander.Content>
<ItemsPresenter Margin="20,0,0,0" />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander>
<Expander.Content>
<ListView ItemsSource="{Binding Items}">
<ListView.View>
<GridView>
<GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}"/>
<GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}"/>
</GridView>
</ListView.View>
</ListView>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</TreeView.GroupStyle>
</TreeView>

WPF Datagrid Footer by Code Behind => Access Column by Binding

I want make a footer to my DataGrid using this method:
How do I add a footer row in a WPF datagrid?
But, i need to make this by code behind, and that's don't working.
I think it's because the binding of the grid can't find the column.
private DataGridColumn dgInsertCol(ref int idx, DataGridColumn dgc, tblEtatRecapColonne pCol, string pBinding = "") {
var dhHeadName = $"dgHead{pCol.Id}";
dgc.SetValue(NameProperty, dhHeadName);
dgc.HeaderTemplate = GetDtHeader(pCol, pBinding);
dgc.Width = new DataGridLength(1.0, (ckbSize.IsChecked.Value) ? DataGridLengthUnitType.Star : DataGridLengthUnitType.SizeToCells);
dgMain.Columns.Insert(idx++, dgc);
// Faire le footer associé
var t = new TextBlock() { Margin = new Thickness(5, 0, 0, 0), Text = pBinding, Background = new SolidColorBrush(Color.FromRgb(50, 100, 150)) };
var g = new Grid() { MinWidth = 10 };
g.SetBinding(Grid.WidthProperty, new Binding("ActualWidth") { ElementName = dhHeadName, Path=new PropertyPath("ActualWidth", null) }); // DataGridColumn
g.Children.Add(t);
pnlDgFooter.Children.Add(g);
return dgc;
}
<DataGrid Grid.Row="1" x:Name="dgMain" AutoGenerateColumns="False" SelectionUnit="FullRow" LoadingRow="dgMain_LoadingRow" MouseDown="dgMain_MouseDown" Sorting="dgMain_Sorting"
CanUserReorderColumns="False" CanUserResizeColumns="True" CanUserResizeRows="False" CanUserSortColumns="True" CanUserAddRows="False"
Style="{StaticResource dg}" RowStyle="{StaticResource dgRow}" CellStyle="{StaticResource dgCell}" ColumnHeaderStyle="{StaticResource dgColHeader}" RowHeaderStyle="{StaticResource dgRowHeader}"
ItemsSource="{Binding NotifyOnSourceUpdated=True, Source={StaticResource cvsElmts}}" HorizontalAlignment="Left">
<!--DataGrid.DataContext><Binding Source="{StaticResource tblUsers}"/></DataGrid.DataContext-->
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<mvvm:EventToCommand Command="{Binding SendCommand, Mode=OneWay}" CommandParameter="{Binding SelectedItem, ElementName=dgMain}" PassEventArgsToCommand="False"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" BorderThickness="1,1,1,5">
<Expander.Header>
<DockPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}" Margin="5,0,0,0" Width="100"/>
<TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount}"/>
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
<!-- Style for groups under the top level. -->
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<DockPanel Background="LightBlue">
<TextBlock Text="{Binding Path=Name}" Foreground="Blue" Margin="30,0,0,0" Width="100"/>
<TextBlock Text="{Binding Path=ItemCount}" Foreground="Blue"/>
</DockPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<StaticResource ResourceKey="rowBtnDetail"/>
</DataGrid.Columns>
</DataGrid>
<StackPanel Grid.Row="2" Name="pnlDgFooter" HorizontalAlignment="Left" Orientation="Horizontal" >
</StackPanel>
Why use ElementName at all? Set the Source of the Binding directly. Also, don't set Path twice, so either write
g.SetBinding(Grid.WidthProperty,
new Binding
{
Source = dgc,
Path = new PropertyPath("ActualWidth")
});
or
g.SetBinding(Grid.WidthProperty, new Binding("ActualWidth") { Source = dgc });

How to do both filtering and grouping listview from SQL

How do I get my listview to do both grouping and filtering because I can only get it to do one of the thing at once. I had tried almost everything I could but none of it worked. when i remove
public string SelectedParam { get { return _selectedParam; } set { _selectedParam = value; OnPropertyChanged("SelectedParam");
if (_selectedParam == "Krydsmål") { BindData(); } else { hjuldata.ItemsSource = FilterKategori().Tables[0].DefaultView; ; } } }
then the grouping works but the filtering doesn't
i wonder if i can use the sql for filling instead for both filling and filtering and then get the listview to do the filtering like you can do with manualy added items
My combobox for filtering:
<ComboBox x:Name="Krydsmålbox" Foreground="#FFEAEAEA" Background="#FF303030" FontSize="12"
Style="{StaticResource ComboBoxTest2}" ItemTemplate="{StaticResource cmbTemplate2}"
ItemsSource="{Binding}" SelectedValuePath="Krydsmålene"
SelectedValue = "{Binding SelectedParam, RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}},UpdateSourceTrigger=PropertyChanged}" BorderBrush="#FF303030" Height="40" DockPanel.Dock="Top" Margin="586,42,379,0"/>
Listview
<ListView x:Name="hjuldata" BorderBrush="#FF303030" Foreground="#FF00FB0B" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto" Background="#FF303030" ItemsSource="{Binding}" Margin="-160,242,11,22" Grid.ColumnSpan="6" Grid.Row="3" Style="{DynamicResource ListViewStyle2}" DockPanel.Dock="Bottom" Height="576">
<ListView.View>
<GridView>
<GridView.ColumnHeaderContainerStyle>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Background" Value="Black" />
<Setter Property="Foreground" Value="#FFEAEAEA"/>
<Setter Property="FontWeight" Value="Bold" />
</Style>
</GridView.ColumnHeaderContainerStyle>
<GridViewColumn Header="" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Billed, Converter={StaticResource nullImageConverter}}" Width="20" Height="20" Stretch="Fill" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,0,15,0"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Model" Width="140" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Txt" Text="{Binding Model}" Foreground="#FF00FB0B" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Årgang" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Txt" Text="{Binding Årgang}" Foreground="#FF00FB0B" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Motor Type" Width="150" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Txt" Text="{Binding [Motor Type]}" Foreground="#FF00FB0B" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Txt" Text="{Binding Krydsmålet}" Foreground="#FF00FB0B" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Txt" Text="{Binding Centerhul}" Foreground="#FF00FB0B" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="ET" Width="auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Txt" Text="{Binding ET}" Foreground="#FF00FB0B" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Bolter" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Txt" Text="{Binding Bolter}" Foreground="#FF00FB0B" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Dæk" Width="300">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Txt" Text="{Binding Dæk}" Foreground="#FF00FB0B" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Fælge" Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Txt" Text="{Binding Fælge}" Foreground="#FF00FB0B" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
grouping style
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="False" BorderBrush="#FFEAEAEA" BorderThickness="0,0,0,1" >
<Expander.Header>
<StackPanel Orientation="Horizontal" DataContext="{Binding Items}">
<Image Source="{Binding Billed, Converter={StaticResource nullImageConverter}}" Width="20" Height="20" Stretch="Fill" VerticalAlignment="Center" Margin="0,0,15,0"/>
<TextBlock Text="{Binding Mærke}" FontWeight="Bold" Foreground="#FFEAEAEA" FontSize="22" VerticalAlignment="Bottom" />
<TextBlock Text="{Binding Krydsmålene}" FontWeight="Bold" Foreground="#FFFBFB00" FontSize="22" VerticalAlignment="Bottom" Margin="0,0,150,0" TextAlignment="Center" />
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
CS:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _selectedParam;
public MainWindow()
{
InitializeComponent();
BindData();
ICollectionView dataView = CollectionViewSource.GetDefaultView(hjuldata.ItemsSource);
dataView.GroupDescriptions.Add(new PropertyGroupDescription("Mærke"));
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string SelectedParam { get { return _selectedParam; } set { _selectedParam = value; OnPropertyChanged("SelectedParam");
if (_selectedParam == "Krydsmål") { BindData(); } else { hjuldata.ItemsSource = FilterKategori().Tables[0].DefaultView; ; } } }
private void BindData()
{
hjuldata.ItemsSource = Kategori().Tables[0].DefaultView;
}
public DataSet Kategori()
{
Data = #"Select ps.Mærket AS Mærke, P.DataID, P.Billed, P.Model, P.Årgang, P.[Motor Type], P.Krydsmålet, P.Centerhul, P.ET,P.Bolter, P.Dæk, P.Fælge ,PS.Krydsmålene from Data.Hjuldata P inner join Data.Mærke PS on P.MærkeID = PS.MærkeID ORDER BY ps.Mærket";
//SQL statement to fetch entries from Hjuldata
DataSet dsdata = new DataSet();
//Open SQL Connection
using (conn = new SqlConnection(connStrings))
{
conn.Open();
//Initialize command object
using (cmd = new SqlCommand(Data, conn))
{
SqlDataAdapter adapters = new SqlDataAdapter(cmd);
//Fill the result set
adapters.Fill(dsdata);
conn.Close();
}
}
return dsdata;
}
public DataSet FilterKategori()
{
Data = #"Select ps.Mærket AS Mærke, P.DataID, P.Billed, P.Model, P.Årgang, P.[Motor Type], P.Krydsmålet, P.Centerhul, P.ET,P.Bolter, P.Dæk, P.Fælge ,PS.Krydsmålene from Data.Hjuldata P inner join Data.Mærke PS on P.MærkeID = PS.MærkeID WHERE Krydsmålet = #param1";
//SQL statement to fetch entries from products
DataSet dsdata = new DataSet();
//Open SQL Connection
using (conn = new SqlConnection(connStrings))
{
conn.Open();
//Initialize command object
using (cmd = new SqlCommand(Data, conn))
{
cmd.Parameters.AddWithValue("#param1", SelectedParam);
SqlDataAdapter adapters = new SqlDataAdapter(cmd);
//Fill the result set
adapters.Fill(dsdata);
conn.Close();
}
}
return dsdata;
}
Can somebody help me with this please?
I think your problem is that you are using the ADO.NET data view abstraction rather than the WPF data view abstraction which should be easier to use. In WPF when you bind a collection or DataTable to an ItemsControl a data view object is created that basically serves as a layer over your collection or DataTable. By doing this you can potentially have the same collection bound to multiple ItemsControls but have different "views" of that data by having different filtering and grouping for the two distinct data views that are created for that same collection.
In your case you are binding to a DataTable which is messier than binding just to a collection that implements IList. For DataTable there is a DataView class that is part of ADO.NET that your WPF data view will basically serve as a layer over and this DataView is more limited in functionality (this ADO.NET DataView is what you are using in your code currently).
Either way, to get the WPF data view you just need to ask the ItemsSource for it like so:
ICollectionView dataView = CollectionViewSource.GetDefaultView(myListView.ItemsSource);
Now you will want to cast the ICollectionView to something more useful for setting the filter and grouping. In your case you have a DataTable so you will want to cast that to a BindingListCollectionView. Unfortunately this is more limited than the data view you would get for an IList (which is a ListCollectionView), but you have a DataTable so we will just roll with it for now (I always go with IList so I have never actually implemented a DataTable binding in production before).
The BindingListCollectionView doesn't have an operational Filter property so you have to use its CustomFilter property to specify the partial SQL that you want to use to filter your collection (basically what you would have put in a WHERE clause). As far as grouping goes I haven't ever used it on a DataTable binding but I would hope it just works by updating GroupDescriptions on the data view.
So basically in summary I would grab the WPF data view abstraction rather than the ADO.NET data view abstraction that you are currently using and set the filter and grouping on that. Also I would recommend just bringing in your data as an IList or else converting it to an IList since those are easier to work with in WPF.
i think this is something you should read
How to: Group, Sort, and Filter Data in the DataGrid Control
i had tested that one and it works with your datastructure and you dont have to do anything with your filtering only change out the grouping part and colectionview

Checkbox ListView WPF C#

I will start developing for WPF and I have a doubt.
I created a ListView with the Binding property to the next ExtComandaDTO the object. The property in "seleciona" has relationship with a checkbox, but I have following problem.
When I click the checkbox it calls the normal event, but when I change the value of "seleciona" at runtime checkbox in my listview is selected but does not call the event check.
There is missing from Listview to be called the event some attribute?
<ListView x:Name="LvwComanda" Grid.Column="0"
Background="{x:Null}"
Margin="40,36,40,40"
SelectedItem="{Binding SelectedExtComanda}"
ItemsSource="{Binding ObsExtComanda, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.RowSpan="2" >
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Finaliza Comanda" Checked="LvwComandaRowFinalizaComanda_Click" Unchecked="LvwComandaRowFinalizaComanda_Click"></MenuItem>
</ContextMenu>
</ListView.ContextMenu>
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding finaliza_pendente}" Value="true">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding finalizada}" Value="true">
<Setter Property="Foreground" Value="DarkViolet" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Resources>
<ListView.View>
<GridView >
<GridViewColumn Width="30">
<GridViewColumn.CellTemplate>
<DataTemplate >
<CheckBox Name="ChkComanda" IsChecked="{Binding seleciona.IsChecked, Mode=TwoWay}" Checked="Checked_LvwComandaRow" Unchecked="Unchecked_LvwComandaRow" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="Auto" Header="Comanda" DisplayMemberBinding="{Binding nr_comanda}"/>
<GridViewColumn Width="Auto" Header="Taxa Servico" DisplayMemberBinding="{Binding taxa_servico}" />
<GridViewColumn Width="Auto" Header="Finalizada" DisplayMemberBinding="{Binding finalizada, Converter={StaticResource ReplaceConvertSimNao}}" />
<GridViewColumn Width="Auto" Header="Observacao" DisplayMemberBinding="{Binding observacao}"/>
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" BorderBrush="#FFA4B97F" BorderThickness="0,0,0,1">
<Expander.Header>
<DockPanel>
<DockPanel.ContextMenu>
<ContextMenu Loaded="LvwComandaHeaderContextMenu_Loaded">
<MenuItem Header="Libera Mesa" Checked="LvwComandaHeaderLiberaMesa_Click" Unchecked="LvwComandaHeaderLiberaMesa_Click" />
</ContextMenu>
</DockPanel.ContextMenu>
<CheckBox x:Name="HeaderCheckBox" Checked="Checked_LvwComandaHeader" Unchecked="Unchecked_LvwComandaHeader">
<StackPanel Orientation="Horizontal">
<TextBlock FontWeight="Bold" Text="{Binding Name, Converter={StaticResource ReplaceConvertMesaId}}" Margin="5,0,0,0"/>
<TextBlock Width="Auto" Text=" " />
<TextBlock FontWeight="Bold" Width="Auto" Text="{Binding Name, Converter={StaticResource ReplaceConvertMesaGrupo}}" />
<TextBlock Text=" ("/>
<TextBlock Text="{Binding ItemCount, Converter={StaticResource ReplaceConvertComanda}}"/>
<TextBlock Text=")"/>
</StackPanel>
</CheckBox>
</DockPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
#region Event List Row Comanda
private void Checked_LvwComandaRow(object sender, RoutedEventArgs e)
{
this.Handle_LvwComandaRow((CheckBox)sender, true);
}
private void Unchecked_LvwComandaRow(object sender, RoutedEventArgs e)
{
this.Handle_LvwComandaRow((CheckBox)sender, false);
}
private void Handle_LvwComandaRow(CheckBox sender, bool check)
{
if (sender.DataContext is ExtComandaDTO)
{
var row = (ExtComandaDTO)sender.DataContext;
if (check)
{
ObsExtComanda.FindAll(c => c.seleciona && c.id_mesa != row.id_mesa).ForEach(c => c.seleciona = false);
}
bool bolComandaSelected = ObsExtComanda.Exists(c => c.seleciona);
BtPagamento.IsEnabled = bolComandaSelected;
BtImprimir.IsEnabled = bolComandaSelected;
this.PrepareObsPedido(check, row);
this.PrepareObsComandaPagto(check, row);
}
}
public class ExtComandaDTO : ComandaDTO, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
private Boolean _seleciona;
private Boolean _finaliza_pendente;
public Boolean seleciona
{
get { return _seleciona; }
set { _seleciona = value; OnPropertyChanged("seleciona"); }
}
public new Boolean finaliza_pendente
{
get { return _finaliza_pendente; }
set { _finaliza_pendente = value; OnPropertyChanged("finaliza_pendente"); }
}
}
Checked and Unchecked are events fired by the UI (not a set).
Handle that stuff in the set if you want to catch changes from code.

Gridsplitter in a Grid with an ItemsControl

I'm trying to make a PropertyGrid Custom Control. The PropertyGrid will be very similar to the PropertyGrid used in Visual Studio. I've tried using the PropertyGrid of the Extended WPF Toolkit but you have to specify the category of a property with an attribute and we need to change the categories runtime. Which as far as I know is impossible with attributes.
So I'm making the PropertyGrid myself. This is my code so far:
The Generic.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:HomeMadePropertyGrid"
xmlns:System="clr-namespace:System;assembly=mscorlib">
<BooleanToVisibilityConverter x:Key="BoolToVisConverter"></BooleanToVisibilityConverter>
<SolidColorBrush x:Key="GlyphBrush" Color="#444" />
<ControlTemplate x:Key="toggleButtonTemplate" TargetType="ToggleButton">
<Grid Width="15" Height="13" Background="Transparent">
<Path x:Name="ExpandPath" Fill="{StaticResource GlyphBrush}" Data="M 4 0 L 8 4 L 4 8 Z" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="1,1,1,1" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Data" TargetName="ExpandPath" Value="M 0 4 L 8 4 L 4 8 Z"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="toggleButtonStyle" TargetType="ToggleButton">
<Setter Property="Template" Value="{StaticResource toggleButtonTemplate}" />
</Style>
<Style TargetType="{x:Type local:PropertyGrid}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:PropertyGrid}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ItemsControl ItemsSource="{TemplateBinding ItemsSource}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Background="{Binding GridColor, RelativeSource={RelativeSource AncestorType=local:PropertyGrid}}">
<StackPanel Orientation="Horizontal">
<ToggleButton x:Name="toggleButton" Height="20" Width="20" Style="{StaticResource toggleButtonStyle}"/>
<TextBlock Text="{Binding Name}" FontWeight="Bold"></TextBlock>
</StackPanel>
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Visibility="{Binding ElementName=toggleButton, Path=IsChecked, Converter={StaticResource BoolToVisConverter}}"
Grid.IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border BorderThickness="1" BorderBrush="{Binding GridColor, RelativeSource={RelativeSource AncestorType=local:PropertyGrid}}">
<TextBlock Background="White" Text="{Binding Path=Name}"/>
</Border>
<GridSplitter Width="1"
Grid.RowSpan="4" Grid.Column="1"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Background="{Binding GridColor, RelativeSource={RelativeSource AncestorType=local:PropertyGrid}}"/>
<Border Grid.Column="2" BorderThickness="1" BorderBrush="{Binding GridColor, RelativeSource={RelativeSource AncestorType=local:PropertyGrid}}">
<ContentPresenter Grid.Column="2" Content="{Binding Value}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type System:String}">
<TextBox Text="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
BorderThickness="0"/>
</DataTemplate>
<DataTemplate DataType="{x:Type System:Int32}">
<TextBox Text="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
TextAlignment="Right"
BorderThickness="0"/>
</DataTemplate>
<DataTemplate DataType="{x:Type System:Double}">
<TextBox Text="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
TextAlignment="Right"
BorderThickness="0"/>
</DataTemplate>
<DataTemplate DataType="{x:Type System:Boolean}">
<CheckBox IsChecked="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
HorizontalAlignment="Center"/>
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
PropertyGrid.cs
public class PropertyGrid : ItemsControl
{
public Brush GridColor
{
get { return (Brush)GetValue(GridColorProperty); }
set { SetValue(GridColorProperty, value); }
}
public static readonly DependencyProperty GridColorProperty =
DependencyProperty.Register("GridColor", typeof(Brush), typeof(PropertyGrid), new UIPropertyMetadata(new SolidColorBrush(Colors.Transparent)));
static PropertyGrid()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PropertyGrid), new FrameworkPropertyMetadata(typeof(PropertyGrid)));
}
}
PropertyGroup
public class PropertyGroup
{
public string Name { get; set; }
public List<PropertyGridItem> Items { get; set; }
public PropertyGroup()
{
Items = new List<PropertyGridItem>();
Name = "";
}
}
PropertyGridItem
public class PropertyGridItem
{
public string Name { get; set; }
public object Value { get; set; }
public PropertyGridItem(string propertyName, object propertyValue)
{
Name = propertyName;
Value = propertyValue;
}
}
This code in my MainWindow.xaml:
<local:PropertyGrid ItemsSource="{Binding Path=Groups}" GridColor="#f0f0f0"/>
Code behind of my ViewModel:
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
The ViewModel
public class ViewModel
{
public List<PropertyGroup> Groups { get; set; }
public ViewModel()
{
Groups = new List<PropertyGroup>();
PropertyGroup group1 = new PropertyGroup();
group1.Name = "Group1";
group1.Items.Add(new PropertyGridItem("Item1", "test"));
group1.Items.Add(new PropertyGridItem("Item2", 300));
group1.Items.Add(new PropertyGridItem("Item3", true));
group1.Items.Add(new PropertyGridItem("Item4", 5.2));
Groups.Add(group1);
PropertyGroup group2 = new PropertyGroup();
group2.Name = "Group2";
group2.Items.Add(new PropertyGridItem("Item1", "test"));
group2.Items.Add(new PropertyGridItem("Item2", 300));
group2.Items.Add(new PropertyGridItem("Item3", true));
group2.Items.Add(new PropertyGridItem("Item4", 5.2));
Groups.Add(group2);
}
}
The problem I'm having is that the GridSplitter is applied every row. I want the GridSplitter to be applied to all rows of a group. I understand that this is because I make a new Grid for every item. For the attached properties to work the items have to be a direct child of the Grid.
A DataGrid also isn't an option because the GridSplitter is only available between column headers.
So to make a long story short: how can I use a Grid in an ItemsControl with a GridSplitter that applies to all rows of ideally a group or the entire Grid if that isn't possible.
I finally found the solution to this problem.
To get this to work I had to:
Set the Grid.IsSharedSizeScope to true on the parent ItemsControl.
Set the SharedSizeGroup property on the name column with an arbitrary name.
Remove the star sizing on the name column. Having both the first and third column with star sizing resulted in a stuck GridSplitter for some reason.
Set a fixed width on the GridSplitter, I set the Width to 2.
Set the ResizeBehaviour of the GridSplitter to PreviousAndNext.
Here is a relevant piece of the resulting code:
<ItemsControl ItemsSource="{Binding Items}" Grid.IsSharedSizeScope="True">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Visibility="{Binding ElementName=toggleButton, Path=IsChecked, Converter={StaticResource BoolToVisConverter}}" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="nameColumn"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Style="{StaticResource BodyPropertyGrid_CellBorder}">
<TextBlock Text="{Binding Path=Name}"/>
</Border>
<GridSplitter Grid.Column="1" Width="2"
ResizeBehavior="PreviousAndNext"
Style="{StaticResource BodyPropertyGridSplitter}"/>
<Border Grid.Column="2" Style="{StaticResource BodyPropertyGrid_CellBorder}">
<ContentControl Content="{Binding}"
ContentTemplateSelector="{StaticResource propertyItemTemplateSelector}"/>
</Border>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Unfortunately you didn't provide us with a nice simple piece of code that only demonstrates your problem and I don't have time to get it to compile and run in my test project, so I can only give you suggestions and not tested solutions. Next time, please take the time to show a code example that we can just copy and paste into a project.
You might be able to get your 'stretched' GridSplitter if you join all of the row Grids using the Grid.IsSharedSizeScope Attached Property:
<Grid Visibility="{Binding ElementName=toggleButton, Path=IsChecked, Converter=
{StaticResource BoolToVisConverter}}" Grid.IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" SharedSizeGroup="FirstColumn" />
<ColumnDefinition Width="Auto" SharedSizeGroup="GridSplitterColumn" />
<ColumnDefinition Width="*" SharedSizeGroup="LastColumn" />
</Grid.ColumnDefinitions>
...
</Grid>

Categories