Let's say I have the follwoing listview in xaml:
<ListView Name="myListView" DataContext="{Binding MyProperty}" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ListView.Resources>
<Style TargetType="GridViewColumnHeader">
<Setter Property="Visibility" Value="Collapsed" />
</Style>
</ListView.Resources>
<ListView.View>
<GridView >
<GridViewColumn Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding SomeProperty}" TextAlignment="Center"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
how can I create the same listview with C#?
this is what I have worked out:
ListView myListView = new ListView();
// set bindings
myListView.IsSynchronizedWithCurrentItem = true;
Binding b = new Binding("MyProperty")
{
Source = this
};
myListView.SetBinding(ListView.ItemsSourceProperty, b);
myListView.Resources.Add(; // dont know how to add those resource;
GridView g = new GridView();
GridViewColumn gc = new GridViewColumn();
DataTemplate dt = new DataTemplate(new TextBlock()); // I think this is wrong
g.Columns.Add(gc); // add gridview column
gc.CellTemplate = dt;
myListView.View = g;
Resource adding:
view.Resources.Add(typeof(GridViewColumnHeader),
new Style(typeof(GridViewColumnHeader))
{
Setters =
{
new Setter(GridViewColumnHeader.VisibilityProperty, Visibility.Collapsed)
}
}
);
DataTemplate creating:
var template = new DataTemplate();
var textBlock = new FrameworkElementFactory(typeof(TextBlock));
textBlock.SetBinding(TextBlock.TextProperty, new Binding("SomeProperty"));
textBlock.SetValue(TextBlock.TextAlignmentProperty, TextAlignment.Center);
template.VisualTree = textBlock;
Related
I am trying to understand logic behind XAML in Expander control inside DataGrid. First I created this code in XAML inside the DataGrid and it works fine.
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander>
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Magazyn:" Margin="5" />
<TextBlock Text="{Binding Path=Name}" Margin="5" FontWeight="Bold" Foreground="Blue" />
<TextBlock Text="Liczba produktów:" Margin="5"/>
<TextBlock Text="{Binding Path=ItemCount}" Margin="5" FontWeight="Bold" Foreground="Blue"/>
</StackPanel>
</Expander.Header>
<ItemsPresenter/>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
Then I created it's code behind version and it almost works except of Expander's Header, which works if I use in SetValue method string as the second argument. But if I use a StackPanel instance as in XAML I get an exception. What is the reason of it. Why is StackPanel allowed as Header in XAML and it's not in code behind?
var groupStyle = new GroupStyle();
var style = new Style(typeof(GroupItem));
var setter = new Setter();
var template = new ControlTemplate(typeof(GroupItem));
var stackPanel = new StackPanel();
stackPanel.Orientation = Orientation.Horizontal;
stackPanel.Children.Add(new TextBlock() { Text = "Magazyn:", Margin = new Thickness(5) });
var tb = new TextBlock();
tb.Margin = new Thickness(5);
tb.FontWeight = FontWeights.Bold;
tb.Foreground = Blue;
tb.SetBinding(TextBlock.TextProperty, new Binding("Name"));
stackPanel.Children.Add(tb);
stackPanel.Children.Add(new TextBlock() { Text = "Liczba produktów:", Margin = new Thickness(5) });
tb = new TextBlock();
tb.Margin = new Thickness(5);
tb.FontWeight = FontWeights.Bold;
tb.Foreground = Blue;
tb.SetBinding(TextBlock.TextProperty, new Binding("ItemCount"));
stackPanel.Children.Add(tb);
template.VisualTree = new FrameworkElementFactory(typeof(Expander));
template.VisualTree.SetValue(Expander.HeaderTemplateProperty, stackPanel);
template.VisualTree.AppendChild(new FrameworkElementFactory(typeof(ItemsPresenter)));
setter.Property = TemplateProperty;
setter.Value = template;
style.Setters.Add(setter);
groupStyle.ContainerStyle = style;
groupStyle.ContainerStyle.Setters.Add(setter);
gridProdukty.GroupStyle.Add(groupStyle);
I currently trying to change a cell's width if that row's data has a specified state. Each row displays a MediaRow with several columns, in case of an error (MediaRow's HasError = true) some columns should be hidden and the column 'status' should be enlarged and take the space of the now-hidden-columns.
Due to the requirement to have a user-defined order of the columns, I'm creating the columns programmatically.
Note: I removed several columns (and therefore properties of MediaRow) for readability.
MediaRow:
public class MediaRow : INotifyPropertyChanged
{
private string _status = string.Empty;
private string _barcode = string.Empty;
private string _medgrp = string.Empty;
private bool _infield = false;
private bool _haserror = false;
public string MedGrp
{
get => return _medgrp;
set { _medgrp = value; NotifyPropertyChanged(); }
}
public string Barcode
{
get => return _barcode;
set { _barcode = value; NotifyPropertyChanged(); }
}
public string Status
{
get => return _status;
set
{
_status = value; NotifyPropertyChanged();
HasError = (value.ToLower().StartsWith("error")) ? true : false;
}
}
public bool InField
{
get => return _infield;
set { _infield = value; NotifyPropertyChanged(); }
}
public bool HasError
{
get => return _haserror;
set { _haserror = value; NotifyPropertyChanged(); }
}
public string Description { get; set; }
}
create Columns:
private void PopulateColumns()
{
ObservableCollection<DataGridColumn> _loccolumns = new ObservableCollection<DataGridColumn>();
DataGridTextColumn barcodecolumn = new DataGridTextColumn();
barcodecolumn.Header = ResourceManagerService.GetResourceString("EasyTerminalClient_NG", "ColumnBarcode");
barcodecolumn.Width = new DataGridLength(Settings.Instance.CheckinColumnTable["barcode"], DataGridLengthUnitType.Star);
barcodecolumn.Binding = new Binding { Path = new PropertyPath("Barcode"), Mode = BindingMode.TwoWay };
barcodecolumn.Visibility = Visibility.Hidden;
barcodecolumn.HeaderStyle = new Style(typeof(System.Windows.Controls.Primitives.DataGridColumnHeader));
barcodecolumn.HeaderStyle.Setters.Add(new Setter(Control.HorizontalContentAlignmentProperty, HorizontalAlignment.Left));
barcodecolumn.HeaderStyle.Setters.Add(new Setter(Control.BackgroundProperty, System.Windows.Media.Brushes.Transparent));
barcodecolumn.HeaderStyle.Setters.Add(new Setter(Control.FontSizeProperty, new Binding { Path = new PropertyPath("headerSize"), Source = (EasyCheck.EasyTerminalClient_NG.Util.FontDetails)App.Current.FindResource("FontDetails") }));
DataGridTextColumn medgrpcolumn = new DataGridTextColumn();
medgrpcolumn.Header = ResourceManagerService.GetResourceString("EasyTerminalClient_NG", "ColumnMediaGroup");
medgrpcolumn.Width = new DataGridLength(Settings.Instance.CheckinColumnTable["mediagroup"], DataGridLengthUnitType.Star);
medgrpcolumn.Binding = new Binding { Path = new PropertyPath("MedGrp"), Mode = BindingMode.TwoWay };
medgrpcolumn.Visibility = Visibility.Hidden;
medgrpcolumn.HeaderStyle = new Style(typeof(System.Windows.Controls.Primitives.DataGridColumnHeader));
medgrpcolumn.HeaderStyle.Setters.Add(new Setter(Control.HorizontalContentAlignmentProperty, HorizontalAlignment.Left));
medgrpcolumn.HeaderStyle.Setters.Add(new Setter(Control.BackgroundProperty, System.Windows.Media.Brushes.Transparent));
medgrpcolumn.HeaderStyle.Setters.Add(new Setter(Control.FontSizeProperty, new Binding { Path = new PropertyPath("headerSize"), Source = (EasyCheck.EasyTerminalClient_NG.Util.FontDetails)App.Current.FindResource("FontDetails") }));
medgrpcolumn.CellStyle = new Style(typeof(DataGridCell));
medgrpcolumn.CellStyle.Setters.Add(new Setter(DataGridCell.VisibilityProperty, new Binding() { Path = new PropertyPath("HasError"), Mode = BindingMode.OneWay, Converter = new InverseBool2VisibilityConverter() }));
DataGridTextColumn statuscolumn = new DataGridTextColumn();
statuscolumn.Header = ResourceManagerService.GetResourceString("EasyTerminalClient_NG", "ColumnState");
statuscolumn.Width = new DataGridLength(Settings.Instance.CheckinColumnTable["state"], DataGridLengthUnitType.Star);
statuscolumn.Binding = new Binding() { Path = new PropertyPath("Status"), Mode = BindingMode.OneWay, Converter = new LanguageConverter(), FallbackValue = "???" };
statuscolumn.Visibility = Visibility.Hidden;
statuscolumn.HeaderStyle = new Style(typeof(System.Windows.Controls.Primitives.DataGridColumnHeader));
statuscolumn.HeaderStyle.Setters.Add(new Setter(Control.HorizontalContentAlignmentProperty, HorizontalAlignment.Left));
statuscolumn.HeaderStyle.Setters.Add(new Setter(Control.BackgroundProperty, System.Windows.Media.Brushes.Transparent));
statuscolumn.HeaderStyle.Setters.Add(new Setter(Control.FontSizeProperty, new Binding { Path = new PropertyPath("headerSize"), Source = (EasyCheck.EasyTerminalClient_NG.Util.FontDetails)App.Current.FindResource("FontDetails") }));
statuscolumn.CellStyle = new Style(typeof(DataGridCell));
//statuscolumn.CellStyle.Setters.Add(new Setter(DataGridCell.MarginProperty, "-5,-5,-5,0"));
//statuscolumn.CellStyle.Setters.Add(new Setter(DataGridCell.ActualWidthProperty, 500.0));
if (Settings.Instance.CheckinColumnSequence != null)
{
//string columnnames = "number|barcode|title|mediagroup|branch|expires|fee|state|imagestate|";
string[] columnSequence = Settings.Instance.CheckinColumnSequence;
for (int i = 0; i < columnSequence.Length; i++)
{
DataGridColumn thiscolumn = null;
switch (columnSequence[i])
{
case "barcode":
thiscolumn = barcodecolumn;
break;
case "mediagroup":
thiscolumn = medgrpcolumn;
break;
case "state":
thiscolumn = statuscolumn;
break;
}
if (thiscolumn != null)
{
thiscolumn.Visibility = Visibility.Visible;
thiscolumn.DisplayIndex = i;
_loccolumns.Add(thiscolumn);
}
}
ColumnCollection = _loccolumns;
}
}
XAML:
<UserControl.Resources>
<DataTemplate x:Key="RowDetailTemplate">
<Grid x:Name="RowDetailGrid"
Width="952"
Height="Auto"
Margin="5">
<Border HorizontalAlignment="Left"
VerticalAlignment="Top"
CornerRadius="5">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="WhiteSmoke" />
<GradientStop Offset="0.75" Color="#AAFFFFAA" />
<GradientStop Offset="1" Color="#AAFFD455" />
</LinearGradientBrush>
</Border.Background>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Margin="10"
HorizontalAlignment="Center"
FontSize="{Binding headerSize, Source={StaticResource FontDetails}}"
FontWeight="Black"
Text="Weitere Details" />
<TextBlock Grid.Row="1"
Margin="10"
HorizontalAlignment="Left"
Text="{Binding Description}"
TextWrapping="WrapWithOverflow" />
</Grid>
</Border>
<Border Margin="0,0,0,0" CornerRadius="5">
<Border.Background>
<RadialGradientBrush Center="0.5,1" GradientOrigin="0,1" Opacity="0.3" RadiusX="0.8" RadiusY="0.8">
<GradientStop Offset="1" Color="#AACCCCCC" />
<GradientStop Offset="1" Color="WhiteSmoke" />
</RadialGradientBrush>
</Border.Background>
</Border>
</Grid>
</DataTemplate>
</UserControl.Resources>
<DataGrid x:Name="dataGrid1"
Margin="10,10,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
AlternationCount="2"
AutoGenerateColumns="False"
c:DataGridColumnsBehavior.BindableColumns="{Binding ColumnCollection, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding MediaRowCollection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged }"
MinRowHeight="26"
RowDetailsTemplate="{StaticResource RowDetailTemplate}"
RowDetailsVisibilityChanged="dataGrid1_RowDetailsVisibilityChanged"
Loaded="dataGrid1_Loaded"
Width="952"
IsReadOnly="True"
SelectionMode="Single"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserSortColumns="False"
CanUserResizeRows="False"
HorizontalScrollBarVisibility="Disabled"
AreRowDetailsFrozen="True"
HeadersVisibility="Column" VerticalScrollBarVisibility="Auto" >
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding InField}" Value="False">
<Setter Property="Background" Value="Transparent"/>
</DataTrigger>
<DataTrigger Binding="{Binding InField}" Value="True">
<Setter Property="Background" Value="#ffffffac"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<ToggleButton x:Name="RowHeaderToggleButton"
Click="ToggleButton_Click"
Cursor="Hand"/>
</DataTemplate>
</DataGrid.RowHeaderTemplate>
</DataGrid>
In the first steps I ignored the HasError-condition and just tried to apply the desired effect to the status-cells but with no success. I'm just getting an unhandled exception. (The respective code I left as comments in the 'Create Columns' -Section.)
System.ArgumentException: '"-5,-5,-5,0" ist kein gültiger Wert für die
Eigenschaft "System.Windows.FrameworkElement.Margin" auf einem
"Setter".'
should translate to:
System.ArgumentException: '"-5,-5,-5,0" is no valid Value for the property "System.Windows.FrameworkElement.Margin" on a "Setter".'
Question:
How can I achieve the desired effect?
If MediaRow's HasError == true the MedGrp-cell should be hidden and the Status-cell should take up the MedGrp-cells's space.
I'd be happy about any suggestions, even if it is only for a fixed-value for the new status-width.
You can't set the Margin property to a string. You should set it to a Thickness:
statuscolumn.CellStyle.Setters.Add(new Setter(DataGridCell.MarginProperty, new Thickness(-5,-5,-5,0))));
This should get rid of the ArgumentException you are getting.
i'm working on a new program that will show information about Test on some Tools in my factory.
For doing that i'm creating a DataGrid Control at run time and populate it.This part is working very well.
My problem is to add RowDetails, How can i do that in code behind?
if (datatable.Rows.Count != 0)
{
foreach (DataRow dt in datatable.Rows)
{
if (last_tool_test == "" || last_tool_test != dt[1].ToString())
{
last_tool_test = dt[1].ToString();
txt = new TextBlock();
txt.Text = dt[1].ToString() + " :";
txt.TextDecorations = TextDecorations.Underline;
txt.HorizontalAlignment = HorizontalAlignment.Center;
txt.Margin = new Thickness(0, 0, 0, 7);
data = new DataGrid();
data.Width = double.NaN;
data.Margin = new Thickness(5, 0, 5, 5);
data.HeadersVisibility = DataGridHeadersVisibility.Column;
data.CanUserAddRows = false;
data.CanUserDeleteRows = false;
data.CanUserReorderColumns = false;
data.CanUserResizeColumns = false;
data.CanUserSortColumns = false;
data.IsReadOnly = true;
data.SelectionMode = DataGridSelectionMode.Extended;
DataGridTextColumn col1 = new DataGridTextColumn();
col1.Header = "Recipe Name";
col1.Binding = new Binding("Recipe_Name");
col1.Width = new DataGridLength(1, DataGridLengthUnitType.Star);
var style = new Style(typeof(DataGridColumnHeader));
style.Setters.Add(new Setter()
{
Property = HorizontalAlignmentProperty,
Value = HorizontalAlignment.Stretch
});
style.Setters.Add(new Setter()
{
Property = HorizontalContentAlignmentProperty,
Value = HorizontalAlignment.Center
});
style.Setters.Add(new Setter()
{
Property = FontWeightProperty,
Value = FontWeights.Bold
});
var style1 = new Style(typeof(TextBlock));
style1.Setters.Add(new Setter()
{
Property = HorizontalAlignmentProperty,
Value = HorizontalAlignment.Center
});
col1.HeaderStyle = style;
col1.ElementStyle = style1;
data.Columns.Add(col1);
DataGridTextColumn col2 = new DataGridTextColumn();
col2.Header = "Foup";
col2.Width = 100;
col2.Binding = new Binding("Foup");
col2.HeaderStyle = style;
col2.ElementStyle = style1;
data.Columns.Add(col2);
DataGridTextColumn col3 = new DataGridTextColumn();
col3.Header = "Need Reference?";
col3.Width = 110;
col3.HeaderStyle = style;
col3.ElementStyle = style1;
col3.Binding = new Binding("Reference");
data.Columns.Add(col3);
DataGridTextColumn col4 = new DataGridTextColumn();
col4.Header = "# Iteration";
col4.Width = 100;
col4.HeaderStyle = style;
col4.ElementStyle = style1;
col4.Binding = new Binding("Iteration");
data.Columns.Add(col4);
DataGridTextColumn col5 = new DataGridTextColumn();
col5.Header = "Spec";
col5.Width = 100;
col5.HeaderStyle = style;
col5.ElementStyle = style1;
data.Columns.Add(col5);
col5.Binding = new Binding("Spec");
st.Children.Add(txt);
st.Children.Add(data);
}
data.Items.Add(new Tool_Test() { Recipe_Name = dt[2].ToString(), Foup = dt[3].ToString(), Reference = dt[4].ToString(), Iteration = dt[5].ToString(), Spec = dt[6].ToString() });
}
last_tool_test = "";
}
}
edit: I think i found a solution by using resource:
<Window.Resources>
<DataTemplate x:Key="CustomTemplate">
<DataGrid x:Name="datagrid1" HeadersVisibility="Column" CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="False" SelectionMode="Extended" Margin="5,0,5,50" CanUserResizeColumns="False" AutoGenerateColumns="False" VerticalAlignment="Top" IsReadOnly="True" Width="750">
<DataGrid.Columns>
<DataGridTextColumn Header="Sub Test Name" Width="*" Binding="{Binding Path=Recipe_Name}">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="FontWeight" Value="Bold" />
</Style>
</DataGridTextColumn.HeaderStyle>
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Spec" Width="*" Binding="{Binding Path=Foup}">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="FontWeight" Value="Bold" />
</Style>
</DataGridTextColumn.HeaderStyle>
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</Window.Resources>
and in my code i added this:
data.RowDetailsTemplate = (DataTemplate)this.Resources["CustomTemplate"];
Now it's half working. I don't have experience with resource so i can't find a solution to Bind data to it. How can i do that?
Thank you for your help.
You could set the RowDetailsTemplate property to a DataTemplate that you create programmatically using the XamlReader class, e.g.:
string template = "<DataTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x = \"http://schemas.microsoft.com/winfx/2006/xaml\"><TextBlock Text=\"some text...\"></DataTemplate>";
data.RowDetailsTemplate = XamlReader.Parse(template) as DataTemplate;
I have built something along those lines a generic User Control that you can throw any ObservableCollection of objects at it and it will build the table, but you want to define the headers column widths etc. so it doesn't just use the function names for headers and default widths.
First I created an object to hold the settings for each column:
public DataGridColumnSettings(string Header, int ColumnIndex, bool IsReadOnly = true, string Width = "100", bool ComboBoxColumn = false, bool CheckBoxColumn = false)
{
this.Header = Header;
this.ColumnIndex = ColumnIndex;
this.IsReadOnly = IsReadOnly;
this.Width = Width;
this.ComboBoxColumn = ComboBoxColumn;
this.CheckBoxColumn = CheckBoxColumn;
}
I then make a collection of these for each Model (I was using the MVVM pattern):
public static Dictionary<string, DataGridColumnSettings> ColumnSettings
{
get { return new Dictionary<string, DataGridColumnSettings>() { { "PurchaseOrder", new DataGridColumnSettings("Order Number", 0) }, { "Width", new DataGridColumnSettings("Width", 1) }, { "Length", new DataGridColumnSettings("Length", 2) }, { "NumberOfPallets", new DataGridColumnSettings("No of Pallets", 3) }, { "BoardsPerStack", new DataGridColumnSettings("No of Boards", 4) }, { "NumberOfBoards", new DataGridColumnSettings("Total Boards", 5) } }; ; }
}
The dictionary keys are the get set methods from the model for the required value in the table row (this is what the columns will be called by default)
and pass in this dictionary when creating the view object (UserControl) and store it inside the View:
v_DataTable View = new v_DataTable(Model.ColumnSettings);
now add a handler for the data grids Auto Generating Column event:
<DataGrid AutoGeneratingColumn="dataGrid_AutoGeneratingColumn" /> (xaml)
and add the handler to the code behind:
private void dataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
string headername = e.Column.Header.ToString();
//// Any column not in header details is a hidden column
if (this.headerDetails.ContainsKey(headername))
{
Style centerStyle = new Style { TargetType = typeof(DataGridCell) };
centerStyle.Setters.Add(new Setter(TextBlock.TextAlignmentProperty, TextAlignment.Center));
Style headerCenterStyle = new Style { TargetType = typeof(DataGridColumnHeader) };
headerCenterStyle.Setters.Add(new Setter(HorizontalContentAlignmentProperty, HorizontalAlignment.Center));
try
{
e.Column.Width = Double.Parse(this.headerDetails[headername].Width);
}
catch(Exception ex)
{
e.Column.Width = 100;
}
// You can also add bindings here if required
Binding headerTextBinding = new Binding();
headerTextBinding.Source = this.headerDetails[headername];
headerTextBinding.Path = new PropertyPath("Header");
headerTextBinding.Mode = BindingMode.TwoWay;
headerTextBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
BindingOperations.SetBinding(e.Column, DataGridTextColumn.HeaderProperty, headerTextBinding);
e.Column.HeaderStyle = headerCenterStyle;
e.Column.DisplayIndex = this.headerDetails[headername].ColumnIndex; //// If you have issues with the index been out of range, change the order of the get/set functions in the model class
e.Column.CellStyle = centerStyle; //// putting the get/set for any fields that are not displayed first will also help to avoid the issue
e.Column.IsReadOnly = this.headerDetails[headername].IsReadOnly;
}
else
{
e.Column.Visibility = Visibility.Hidden;
}
}
here you can use the settings you passed in to customise the columns as you require. (Should this be in the View Model if following MVVM pattern?)
I think i found a solution by using resource:
<Window.Resources>
<DataTemplate x:Key="CustomTemplate">
<DataGrid x:Name="datagrid1" HeadersVisibility="Column" CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="False" SelectionMode="Extended" Margin="5,0,5,50" CanUserResizeColumns="False" AutoGenerateColumns="False" VerticalAlignment="Top" IsReadOnly="True" Width="750">
<DataGrid.Columns>
<DataGridTextColumn Header="Sub Test Name" Width="*" Binding="{Binding Path=Recipe_Name}">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="FontWeight" Value="Bold" />
</Style>
</DataGridTextColumn.HeaderStyle>
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Spec" Width="*" Binding="{Binding Path=Foup}">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="FontWeight" Value="Bold" />
</Style>
</DataGridTextColumn.HeaderStyle>
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
and in my code i added this:
data.RowDetailsTemplate = (DataTemplate)this.Resources["CustomTemplate"];
Now it's half working. I don't have experience with resource so i can't find a solution to Bind data to it. How can i do that?
I have this code behind :
private void InitializeListView()
{
//RAZ
lv.Items.Clear();
GridView gridView = new GridView();
gridView.AllowsColumnReorder = true;
GridViewColumn gvc1 = new GridViewColumn();
gvc1.DisplayMemberBinding = new System.Windows.Data.Binding("SN");
gvc1.Header = "SN";
GridViewColumn gvc2 = new GridViewColumn();
gvc2.DisplayMemberBinding = new System.Windows.Data.Binding("a1");
gvc2.Header = "A1";
gridView.Columns.Add(gvc2);
GridViewColumn gvc3 = new GridViewColumn();
gvc3.DisplayMemberBinding = new System.Windows.Data.Binding("a2");
gvc3.Header = "A2";
gridView.Columns.Add(gvc3);
for (int i = 0; i < lv.Count; i++)
{
this.lv.Items.Add(
new dataToUse
{
sn= tab[i][0],
a1= tab[i][1],
a2 = tab[i][2]
});
}
this.lv.View = gridView;
}
in order to generate dinamycally this :
<ListView x:Name="lv" HorizontalAlignment="Left" Height="360" Margin="305,192,0,0" VerticalAlignment="Top" Width="607" SelectionMode="Extended" >
<ListView.View >
<GridView AllowsColumnReorder="true">
<GridViewColumn DisplayMemberBinding="{Binding sn}" >
<GridViewColumnHeader>
<GridViewColumnHeader.ContextMenu>
<ContextMenu>
<MenuItem Header="Asc"/>
<MenuItem Header="Desc" />
</ContextMenu>
</GridViewColumnHeader.ContextMenu>
</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding a1}">
<GridViewColumnHeader >
<GridViewColumnHeader.ContextMenu>
<ContextMenu >
<MenuItem Header="Asc" />
<MenuItem Header="Desc" />
</ContextMenu>
</GridViewColumnHeader.ContextMenu>
</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding a2}">
<GridViewColumnHeader >
<GridViewColumnHeader.ContextMenu>
<ContextMenu >
<MenuItem Header="Asc" />
<MenuItem Header="Desc"/>
</ContextMenu>
</GridViewColumnHeader.ContextMenu>
</GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
The problem is that when I generate the project, I cannot see the ContextMenu (and so the MenuItems)
I already use this kind of code in another project, but here, it doesn t work...
I guess the code behind is the last one wich is generated, so if you could explain me how to create a ContextMenu programatically. Could be good.
Could you help me please ?
Thanks !
Here is an example for the A2 column. The others follow the same approach.
// Remove:
//gvc3.Header = "A2";
// Replace by:
gvc3.Header = new GridViewColumnHeader()
{
Content = "A2",
ContextMenu = new ContextMenu()
{
Items =
{
new MenuItem() { Header="Asc"},
new MenuItem() { Header="Desc"}
}
}
};
In order to implement the actual sorting with possibility to sort by multiple columns, the menu items could be created with the following helper functions:
private MenuItem CreateAscendingSortMenuItem(string prop)
{
var result = new MenuItem() { Header = "Asc" };
result.Click += (s, e) =>
{
var toRemove = lv.Items.SortDescriptions.Where(x => x.PropertyName == prop).ToList();
foreach (var item in toRemove)
{
lv.Items.SortDescriptions.Remove(item);
}
lv.Items.SortDescriptions.Insert(0, new SortDescription(prop, ListSortDirection.Ascending));
};
return result;
}
private MenuItem CreateDescendingSortMenuItem(string prop)
{
var result = new MenuItem() { Header = "Desc" };
result.Click += (s, e) =>
{
var toRemove = lv.Items.SortDescriptions.Where(x => x.PropertyName == prop).ToList();
foreach (var item in toRemove)
{
lv.Items.SortDescriptions.Remove(item);
}
lv.Items.SortDescriptions.Insert(0, new SortDescription(prop, ListSortDirection.Descending));
};
return result;
}
Then just create the items using the helper function instead of calling the constructor directly.
gvc3.Header = new GridViewColumnHeader()
{
Content = "A2",
ContextMenu = new ContextMenu()
{
Items =
{
CreateAscendingSortMenuItem("a2"),
CreateDescendingSortMenuItem("a2")
}
}
};
Thanks grek40 !
In addtion to your answer (how to create an event for a MenuItem):
// Remove:
//gvc3.Header = "A2";
// Replace by:
MenuItem item1 = New MenuItem();
item1.Header = "Desc";
//Event
item1+= new RoutedEventHandler(this.someFunction_click);
gvc3.Header = new GridViewColumnHeader()
{
Content = "A2",
ContextMenu = new ContextMenu()
{
Items =
{
new MenuItem() { Header="Asc"},
item1
}
}
};
//Function launched by the event
private void someFunction_Click(object sender, System.EventArgs e)
{
//do something
}
Thank you guys for your help !!!
In code i add columns to listview successfuly. But i want add binding to column than add to listview.
fist is working code in xaml.
<GridViewColumn x:Name="colName" Header="Name" Width="130">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Values, Converter={StaticResource LoadProfileConverter},ConverterParameter=active_total}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
Code behind:
GridViewColumn column = new GridViewColumn();
column.Header = "Header";
column.Width = 130;
FrameworkElementFactory controlFactory = new FrameworkElementFactory(typeof(TextBlock));
var itemsBinding = new System.Windows.Data.Binding("Values")
{
Converter = new LoadProfileConverter(),
ConverterParameter = "active_total",
};
controlFactory.SetBinding(TextBox.TextProperty, itemsBinding);
DataTemplate template = new DataTemplate();
template.VisualTree = controlFactory;
column.CellTemplate = template;
LoadProfileGrid.Columns.Add(column);
var itemsbinding = new Binding("Values")
{
Converter = new LoadProfileConverter(),
ConverterParameter = key
};
controllerFactory.SetBinding(TextBox.TextProperty, itemsbinding);
Create a proper binding using the code above.
Loads of extra properties on the binding object that can assist you.
GridViewColumn column = new GridViewColumn();
column.Header = key;
column.Width = 130;
FrameworkElementFactory controlFactory = new FrameworkElementFactory(typeof(TextBlock));
var itemsBinding = new System.Windows.Data.Binding("Values")
{
Converter = new LoadProfileConverter(),
ConverterParameter = key
};
column.DisplayMemberBinding = itemsBinding;
LoadProfileGrid.Columns.Add(column);