i want to fill a datagrid with the columns "Datum" (DateTime), "Aktion" (String), "Wer" (string),"BisWann" (DateTime), "Status" (int). The "Status" column should be a dropdown list, which contains four icons and dependent on the int value, there should be the correct image preselected.
how can i archive this? So far, i have the datagrid filled with every value, except the dropdownlist (in the following code just a sample entry w/o database)
Window.xaml:
<DataGrid Name="dgMassnahmen" AutoGenerateColumns="False" Margin="10,10,10,10" Grid.Row="1">
<DataGrid.Columns>
<DataGridTextColumn Header="Datum" Binding="{Binding Datum, StringFormat=\{0:dd.MM.yy\}}"/>
<DataGridTextColumn Header="Aktion" Binding="{Binding Aktion}"/>
<DataGridTextColumn Header="Wer" Binding="{Binding Wer}"/>
<DataGridTemplateColumn Header="BisWann">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding BisWann}" BorderThickness="0" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridComboBoxColumn Header="Status" SelectedValueBinding="{Binding Status}"/>
</DataGrid.Columns>
</DataGrid>
the Itemclass:
public class Massnahmen
{
public DateTime Datum { get; set; }
public string Aktion { get; set; }
public string Wer { get; set; }
public DateTime BisWann { get; set; }
public int Status { get; set; }
}
in Window.xaml.cs:
private void FillMassnahmen()
{
List<Klassen.Massnahmen> massnahmen = new List<Klassen.Massnahmen>();
massnahmen.Add(new Klassen.Massnahmen() { Datum = DateTime.Now, Aktion = "DoSomething", BisWann = DateTime.Now.AddDays(2), Status = 2, Wer = "OfCourseYOU" });
dgMassnahmen.ItemsSource = massnahmen;
}
You could set the ItemsSource to an array of Image elements and set the Tag property of each element to an int value that you bind to the Status property:
<DataGridComboBoxColumn Header="Status"
SelectedValueBinding="{Binding Status}"
SelectedValuePath="Tag"
xmlns:s="clr-namespace:System;assembly=mscorlib">
<DataGridComboBoxColumn.ItemsSource>
<x:Array Type="{x:Type Image}">
<Image Source="1.png">
<Image.Tag>
<s:Int32>1</s:Int32>
</Image.Tag>
</Image>
<Image Source="2.png">
<Image.Tag>
<s:Int32>2</s:Int32>
</Image.Tag>
</Image>
</x:Array>
</DataGridComboBoxColumn.ItemsSource>
</DataGridComboBoxColumn>
Related
I am trying to create a DataGrid with two text columns and a template column as follows:
<UserControl
...
Name="TcpNtcpSliders"
...>
<DataGrid Name="MinTcpDataGrid" AutoGenerateColumns="False" Margin="2" Grid.Row="0"
ItemsSource="{Binding MinTcpRows, ElementName=TcpNtcpSliders, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<DataGrid.Columns>
<DataGridTextColumn Header="Structure ID" IsReadOnly="True" Width="Auto"
Binding="{Binding StructureId, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
<DataGridTextColumn Header="Min. TCP" IsReadOnly="True" Width="Auto" x:Name="MinTcpTextColumn"
Binding="{Binding MinTcpValue, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTemplateColumn Header="Set Min. Tcp" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Slider Minimum="0" Maximum="1"
Value="{Binding MinTcpValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</UserControl>
In the code behind I have
internal ObservableCollection<MinTcpRow> MinTcpRows
{
get { return (ObservableCollection<MinTcpRow>)GetValue(MinTcpRowsProperty); }
set { SetValue(MinTcpRowsProperty, value); }
}
internal static readonly DependencyProperty MinTcpRowsProperty =
DependencyProperty.Register("MinTcpRows", typeof(ObservableCollection<MinTcpRow>),
typeof(RtpOptimizationTcpNtcpSliders),
new PropertyMetadata(new ObservableCollection<MinTcpRow>(), MinTcpRowsPropertyChangedCallback));
private static void MinTcpRowsPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (RtpOptimizationTcpNtcpSliders)d;
control.MinTcpRows = (ObservableCollection<MinTcpRow>)e.NewValue;
control.CreateTcpNtcpLimits();
}
and the MinTcpRow class is defined like:
public class MinTcpRow
{
public string StructureId { get; }
public double MinTcpValue { get; set; }
public MinTcpRow(string structureId, double minTcpValue)
{
if (minTcpValue < 0 || minTcpValue > 1)
throw new ArgumentOutOfRangeException($"{nameof(minTcpValue)} must " +
$"be in range [0, 1], but was {minTcpValue}.");
StructureId = structureId ?? throw new ArgumentNullException(nameof(structureId));
MinTcpValue = minTcpValue;
}
}
Everything works as expected, except for the Slider value binding. I says cannot resolve symbol 'MinTcpValue'. How can I bind the slider's value correctly?
In order to see what happens I put a simplified version together.
In my mainwindow I have a datagrid:
<DataGrid Name="MinTcpDataGrid" AutoGenerateColumns="False"
ItemsSource="{Binding Rows}">
<DataGrid.Columns>
<DataGridTextColumn Header="Structure ID" IsReadOnly="True" Width="Auto"
Binding="{Binding StructureId, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
<DataGridTextColumn Header="Min. TCP" IsReadOnly="True" Width="Auto" x:Name="MinTcpTextColumn"
Binding="{Binding MinTcpValue, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTemplateColumn Header="Set Min. Tcp" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Slider Minimum="0" Maximum="1"
Value="{Binding MinTcpValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
MainWindowViewModel will supply my Rows collection:
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
private ObservableCollection<MinTcpRow> rows = new ObservableCollection<MinTcpRow>();
public MainWindowViewModel()
{
rows.Add(new MinTcpRow ("A",0.1));
rows.Add(new MinTcpRow("B", 0.5));
rows.Add(new MinTcpRow("C", 0.9));
}
}
And MinTcpRow ( is faulted because it won't notify change ) but looks the same.
public class MinTcpRow
{
public string StructureId { get; }
public double MinTcpValue { get; set; }
public MinTcpRow(string structureId, double minTcpValue)
{
if (minTcpValue < 0 || minTcpValue > 1)
throw new ArgumentOutOfRangeException($"{nameof(minTcpValue)} must " +
$"be in range [0, 1], but was {minTcpValue}.");
StructureId = structureId ?? throw new ArgumentNullException(nameof(structureId));
MinTcpValue = minTcpValue;
And that works, no error anyhow. There is a memory leak waiting to catch you out because of not implementing inpc but I get no error like you show us. Are you somehow using a different version of MinTcpRow ?
I have two datagrids. The first one is an overview about a time tracking. The second one shows some details.
For example:
The first datagrid contains each day, where a employee works. The second datagrid contains the time stamping for a day.
However, when I add a new stamping row, the controls in the datagrid are empty. That is not really a problem but the datepicker shows the date 01/01/0001.
what i want is when i add a new row, the date field should be filled with the date from the first datagrid.
VIEW:
<DataGrid Grid.Column="0"
IsReadOnly="True"
AutoGenerateColumns="False"
Grid.Row="0"
x:Name="DgStundenView"
Margin="0 0 10 0"
SelectedItem="{Binding SelectedItem}"
ItemsSource="{Binding TimeOverviewList}">
<DataGrid.Columns>
<DataGridTextColumn Header="Wochentag" Binding="{Binding Wochentag}" />
<DataGridTextColumn Header="Datum" Binding="{Binding Tag}" />
<DataGridTextColumn Header="Arbeitszeit Soll" Binding="{Binding ArbeitszeitInStunden}" />
<DataGridTextColumn Header="Arbeitszeit gesamt" Binding="{Binding GesamtDauerInStunden}" />
<DataGridTextColumn Header="Pausenzeit" Binding="{Binding Pausenzeit}" />
<DataGridTextColumn Header="Pausendifferenz" Binding="{Binding PausenDifferenzInStunden}" />
<DataGridTextColumn Header="Arbeitszeit inkl. Pause" Binding="{Binding TatsaechlicheDauerInStunden}" />
<DataGridCheckBoxColumn Header="Status" Binding="{Binding StempelungVorhanden,Mode=OneWay}" />
<DataGridTextColumn Header="Info" Binding="{Binding Info}" />
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Wochentag}" Value="Sa">
<Setter Property="Background" Value="LightGray" />
</DataTrigger>
<DataTrigger Binding="{Binding Wochentag}" Value="So">
<Setter Property="Background" Value="LightGray" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>
<DataGrid Grid.Column="0"
Grid.Row="1"
x:Name="DgStempelungen"
Margin="0 10 10 0"
AutoGenerateColumns="False"
CanUserAddRows="True"
SelectedItem="{Binding SelectedValue}"
ItemsSource="{Binding TimeDetailList}">
<DataGrid.Resources>
<x:Array x:Key="Reasons" Type="system:String">
<system:String>NICHT ANWENDBAR</system:String>
<system:String>KRANK</system:String>
<system:String>GANZER TAG URLAUB</system:String>
</x:Array>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="ID" IsReadOnly="True" Binding="{Binding Id}"/>
<DataGridTemplateColumn Header="KOMMEN DATUM">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding ComeBooking}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="KOMMEN UHRZEIT">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<materialDesign:TimePicker Text="{Binding ComeBookingTime, StringFormat=t}"
Is24Hours="True">
</materialDesign:TimePicker>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="GEHEN DATUM">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding GoBooking}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="GEHEN UHRZEIT">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<materialDesign:TimePicker Text="{Binding GoBookingTime, StringFormat=t}"
Is24Hours="True">
</materialDesign:TimePicker>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridComboBoxColumn Header="GRUND"
ItemsSource="{StaticResource Reasons}"
TextBinding="{Binding Info}"/>
</DataGrid.Columns>
</DataGrid>
VIEW MODEL
[CanBeNull] private ClassTimeTrackingDayStamp _selectedItem;
[CanBeNull]
public ClassTimeTrackingDayStamp SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
OnPropertyChanged();
if (_selectedItem != null)
TimeDetailList = new ObservableCollection<ClassTimeTrackingTimeStamp>(_selectedItem.Stempelungen);
}
}
private ObservableCollection<ClassTimeTrackingDayStamp> _timeOverviewList;
public ObservableCollection<ClassTimeTrackingDayStamp> TimeOverviewList
{
get { return _timeOverviewList; }
set
{
_timeOverviewList = value;
OnPropertyChanged();
}
}
[CanBeNull] private ObservableCollection<ClassTimeTrackingTimeStamp> _timeDetailList;
[CanBeNull]
public ObservableCollection<ClassTimeTrackingTimeStamp> TimeDetailList
{
get { return _timeDetailList; }
set
{
_timeDetailList = value;
OnPropertyChanged();
}
}
MODEL
public class ClassTimeTrackingTimeStamp : ViewModelBase
{
public DateTime ComeBooking { get; set; }
public DateTime GoBooking { get; set; }
public TimeSpan ComeBookingTime { get; set; }
public TimeSpan GoBookingTime { get; set; }
public int Id { get; set; }
public string Info { get; set; }
}
Update
EVENT OVER MVVM VIEW
<DataGrid Grid.Column="0"
Grid.Row="1"
x:Name="DgStempelungen"
Margin="0 10 10 0"
AutoGenerateColumns="False"
CanUserAddRows="True"
SelectedItem="{Binding SelectedValue}"
ItemsSource="{Binding TimeDetailList}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="AddingNewItem">
<i:InvokeCommandAction Command="{Binding Path=AddNewItemCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
...
VIEW MODEL
public ICommand AddNewItemCommand { get; set; }
#endregion Properties
#region Events
public event EventHandler AddNewItemEventHandler;
#endregion
#region Constructor
public WTimeClockOverviewVM()
{
AddNewItemCommand = new RelayCommand(o =>
{
this.AddNewItemEventHandler?.Invoke(this, EventArgs.Empty);
});
}
CODE BEHIND
public WTimeClockOverview()
{
InitializeComponent();
var vm = (WTimeClockOverviewVM)DataContext;
if(vm == null) return;
vm.AddNewItemEventHandler += (sender, args) =>
{
var selectedItemInFirstDg = vm.SelectedItem;
if (selectedItemInFirstDg != null)
{
var newItem = new ClassTimeTrackingTimeStamp();
newItem.ComeBooking = selectedItemInFirstDg.Tag;
}
};
}
Thank you for your help :)
Best regards
Levin
In second DataGrid, you can subscribe to AddingNewItem event
<DataGrid x:Name="DgStempelungen"
AddingNewItem="DgStempelungen_OnAddingNewItem"
...
In code behind
private void DgStempelungen_OnAddingNewItem(object sender, AddingNewItemEventArgs e)
{
// I'll assume that the Model's Name in first DataGrid collection is StudentItem!
var selectedItemInFirstDg = DgStundenView.SelectedItem as StudentItem;
// or you can get the selected item from the DataContext:
// (DgStundenView.DataContext as MyViewModel)?.SelectedItem;
if (selectedItemInFirstDg != null){
// create the new row with data from selectedItemInFirstDg, ex. date, etc...
e.NewItem = new ClassTimeTrackingDayStamp
{
ComeBooking = selectedItemInFirstDg.Date; // for example
};
}
}
I have a datagrid that is bound to a BindableCollection, this is working properly, every repair order I add to the BindableCollection shows in the Datagrid.
I have a second Datagrid on the same view for "WriteOffs", Each "RepairOrder" has a property of BindableCollection.
What I am trying to do is bind the WriteOff DataGrid to the WriteOffs of the selected row. So every time the user selects a row in the "RepairOrder" datagrid the write offs stored in the writeoff property is shown in the WriteOff datagrid.
What is the best way to handle this?
RepairOrder class:
public string ControlNumber { get; set; }
public double Value { get; set; }
public string Note { get; set; }
public string Schedule { get; set; }
public int Age { get; set; }
public List<WriteOff> WriteOffs { get; set; }
public RepairOrder(string CN, string SC, double VL)
{
ControlNumber = CN;
Schedule = SC;
Value = Math.Round(VL,2);
Note = null;
WriteOffs = new List<WriteOff>();
}
public RepairOrder()
{
}
public void AddWriteOff(WriteOff WO)
{
WriteOffs.Add(WO);
}
public BindableCollection<WriteOff> GetWriteOffs()
{
BindableCollection<WriteOff> temp = new BindableCollection<WriteOff>();
foreach (var item in WriteOffs)
{
temp.Add(item);
}
return temp;
}
public static RepairOrder FromCSV(string CSVLine, string Sched)
{
string[] values = CSVLine.Split(',');
RepairOrder rep = new RepairOrder();
rep.ControlNumber = values[2];
rep.Value = Math.Round(double.Parse(values[5]),2);
rep.Age = int.Parse(values[4]);
rep.Schedule = Sched;
return rep;
}
The XML for the Data grid showing the repair orders:
<Border BorderBrush="Black" BorderThickness="2" CornerRadius="5" Grid.Column="1" Grid.Row="1">
<DataGrid x:Name="ScheduleGrid" ItemsSource="{Binding RepairOrders}" CanUserSortColumns="True" AutoGenerateColumns="False" SelectedIndex="{Binding SelectedRepairOrder}" SelectionMode="Single">
<DataGrid.Columns>
<DataGridTextColumn Header="Schedule" Binding="{Binding Schedule}" Width="75" IsReadOnly="True"/>
<DataGridTextColumn Header="Control Number" Binding="{Binding ControlNumber}" Width="110" IsReadOnly="True"/>
<DataGridTextColumn Header="Age" Binding="{Binding Age}" Width="50" IsReadOnly="True"/>
<DataGridTextColumn Header="Value" Binding="{Binding Value, StringFormat=C}" Width="75" IsReadOnly="True"/>
<DataGridTextColumn Header="Note" Binding="{Binding Note}" Width="*"/>
</DataGrid.Columns>
</DataGrid>
</Border>
XML for the Data grid for the write-offs:
<Border Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" BorderBrush="Black" BorderThickness="2" CornerRadius="5" Margin="5,2,5,5">
<StackPanel Orientation="Vertical">
<TextBlock Text="Write Off List" HorizontalAlignment="Center" FontSize="20"/>
<DataGrid ItemsSource="{Binding WriteOffs}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Account" Binding="{Binding Account}" Width="100" IsReadOnly="True"/>
<DataGridTextColumn Header="Description" Binding="{Binding Description}" Width="200" IsReadOnly="True"/>
<DataGridTextColumn Header="Amount" Binding="{Binding WriteOffAmount}" Width="*" IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</Border>
I was thinking of making an event when the user selects a row, but I can't seem to find a way to get the value if the selected row into the ViewModel method.
I can't seem to find a clear tutorial or post on exactly how to hand this situation.
What is the easiest way to accomplish my final goals?
Okay this is the way I would do...
Instead of SelectedIndex on your ScheduleGrid DataGrid you need to use SelectedItem.
So your XAML would look like this:
<DataGrid x:Name="ScheduleGrid" ItemsSource="{Binding RepairOrders}" SelectedItem="{Binding SelectedRepairOrder} ...."
Not to the ViewModel
Now you need to make the SelectedItem property, or SelectedRepairOrder.
The property should look like this:
private RepairOrder _selectedRepairOrder;
public RepairOrder SelectedRepairOrder
{
get { return _selectedRepairOrder; }
set
{
if (_selectedRepairOrder == value) return;
_selectedRepairOrder = value;
NotifyOfPropertyChange(() => SelectedRepairOrder);
NotifyOfPropertyChange(() => WriteOffsCollection);
}
}
Second, since we have two DataGrids we need also two Collections.
The ScheduleGrid should have a Collection who looks like this:
private BindableCollection<RepairOrder> _repiarOrdersCollection;
public BindableCollection<RepairOrder> RepairOrders
{
get { return _repiarOrdersCollection; }
set
{
_repiarOrdersCollection = value;
}
}
And the WriteOffs DataGrid collection should be like this:
public BindableCollection<WriteOff> WriteOffs
{
get
{
return GetWriteOffs();
}
}
Okay... now what happens... As you can see in your SelectedRepairOrder property, after it changes, it will notify your WriteOffs collection that it has changed. And since we are newer setting the value of its DataGrid, we don't need any setter.
Now one thing is missing. Since you have two collections, I believe that you want after selecting item from one collection to filter the items on other collection? Right? If yes, the you need to extend your GetWriteOffs() method, to have parameters of some king, string, int... and inside it filter your data.
I'm learning XAML with WPF and i'm trying to display some data in a grid, but i can't for the life of me get it to show. the fields appear, but they're empty without text. here's the XAML
<Window x:Class="MoodWPF.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:MoodWPF"
mc:Ignorable="d"
Height="810.573"
Width="1026.432"
MinWidth="600">
<Grid x:Name="mainGrid" Background="#333333">
<DataGrid Width="400" Height="400" x:Name="trackList" HorizontalAlignment="Center" VerticalAlignment="Center" Background="#FF404040" BorderBrush="{x:Null}" ColumnHeaderHeight="22" GridLinesVisibility="Vertical" RowBackground="#FF404040" AlternatingRowBackground="#FF333333" RowHeight="20" SelectionMode="Single">
<DataGrid.Columns>
<DataGridTemplateColumn x:Name="Track" Header="Track" Width="100" IsReadOnly="True">
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Artist" Width="100" IsReadOnly="True">
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Album" Width="100" IsReadOnly="True">
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Time" Width="100" IsReadOnly="True">
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
and the C# with which im trying to insert some random data
namespace MoodWPF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// create and add three lines of fake data to be displayed, here
trackList.Items.Add(new DataItem { Track = "a.1", Artist = "a.2", Album = "a.3", Time = "a.4" });
trackList.Items.Add(new DataItem { Track = "a.1", Artist = "a.2", Album = "a.3", Time = "a.4" });
trackList.Items.Add(new DataItem { Track = "a.1", Artist = "a.2", Album = "a.3", Time = "a.4" });
/*
Collection<DataItem> users = new Collection<DataItem>();
users.Add(new DataItem { Track = "firstname-1", Artist = "lastname-1" });
users.Add(new DataItem { Track = "firstname-2", Artist = "lastname-2" });
users.Add(new DataItem { Track = "firstname-3", Artist = "lastname-3" });
users.Add(new DataItem { Track = "firstname-4", Artist = "lastname-4" });
trackList.ItemsSource = users;
}
}
public class DataItem
{
public string Track { get; set; }
public string Artist { get; set; }
public string Album { get; set; }
public string Time { get; set; }
}
}
what am i doing wrong/not doing? keep in mind i'm a beginner with WPF and Xaml
There are few issues,
(i) You need to have a collection to bind to DataGrid, hence add the items to a List or ObservableCollection
Code Behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<DataItem> data = new List<DataItem>();
data.Add(new DataItem { Track = "a.1", Artist = "a.2", Album = "a.3", Time = "a.4" });
data.Add(new DataItem { Track = "a.1", Artist = "a.2", Album = "a.3", Time = "a.4" });
data.Add(new DataItem { Track = "a.1", Artist = "a.2", Album = "a.3", Time = "a.4" });
trackList.ItemsSource = data;
}
}
public class DataItem
{
public string Track { get; set; }
public string Artist { get; set; }
public string Album { get; set; }
public string Time { get; set; }
}
(ii)Set DataGrid AutoGenerateColumns="True"
If you set AutoGenerateColums= false,
XAML:
<DataGrid Width="400" Height="400" x:Name="trackList" HorizontalAlignment="Center" VerticalAlignment="Center" Background="#FF404040" BorderBrush="{x:Null}" ColumnHeaderHeight="22" GridLinesVisibility="Vertical" RowBackground="#FF404040" AlternatingRowBackground="#FF333333" RowHeight="20" SelectionMode="Single">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Track}" x:Name="Track" Header="Track" Width="100" IsReadOnly="True">
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Artist}" Header="Artist" Width="100" IsReadOnly="True">
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Album}" Header="Album" Width="100" IsReadOnly="True">
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Time}" Header="Time" Width="100" IsReadOnly="True">
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
When you need only text try:
<DataGrid.Columns>
<DataGridTextColumn x:Name="Track" Width="100" Binding="{Binding Track}" Header="Track"/>
...
or you need specific template:
<DataGridTemplateColumn Header="Artist" Width="100" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Artist}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
You must to bind your model (probably a List of specific object) to the DataGrid, and its attributes to its repective columns.
Kind of:
<DataGrid x:Name="TrackList" DataContext="{Binding Source=TrackList}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Track" Binding="{Binding Track}"/>
<DataGridTextColumn Header="Artist" Binding="{Binding Artist}"/>
...........
...........
</DataGrid.Columns>
</DataGrid>
I have a DataGrid, one of the columns is a DataGridComboBoxColumn:
<DataGrid AutoGenerateColumns="False" CanUserAddRows="True">
<DataGrid.Columns>
<DataGridTextColumn Header="User Name" Width="Auto" Binding="{Binding UName}"/>
<DataGridComboBoxColumn Header="Country" Width="Auto" ????/>
</DataGrid.Columns>
</DataGrid>
I have a Country class:
public class Country{
public string name {get; set;}
public string des {get; set;}
public Country() {}
public Country(string n, string d) {
this.name = n;
this.des = d;
}
}
they have a name and a description, I want the names(of multiple Country objects) to populate the combo-box(and the des the tooltip of each combo-box option), how do I do that?
Note: later I would like to give the user the ability to add a new Country, so I would like the combo-box to change as well(to include the new Country), meaning the solution needs to allow that.
Note2: I am not using the MVVM pattern. edit: meaning it is not a duplicate.
Solution:
1. XAML:
<DataGrid x:Name="DataGrid" AutoGenerateColumns="False" CanUserAddRows="True">
<DataGrid.Columns>
<DataGridTextColumn Header="User UName" Width="Auto" Binding="{Binding UName}"/>
<DataGridComboBoxColumn x:Name="ComboBoxColumn" Header="Country" Width="Auto" DisplayMemberPath="name" SelectedItemBinding="{Binding CountryData}"/>
</DataGrid.Columns>
</DataGrid>
2. Code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
InitData();
ComboBoxColumn.ItemsSource = CountriesCollection;
DataGrid.ItemsSource = UsersCollection;
}
private void InitData()
{
UsersCollection = new ObservableCollection<UserData>(new List<UserData>
{
new UserData
{
UName = "Greg",
},
new UserData
{
UName = "Joe",
},
new UserData
{
UName = "Iv",
}
});
CountriesCollection = new ObservableCollection<Country>(new List<Country>
{
new Country("Ger", "1500"),
new Country("Fra", "1500"),
new Country("Ru", "1500"),
new Country("Bel", "1500"),
});
}
public ObservableCollection<Country> CountriesCollection { get; set; }
public ObservableCollection<UserData> UsersCollection { get; set; }
}
3. User model:
public class UserData
{
public string UName { get; set; }
public object CountryData { get; set; }
}
4. tool tip support: replace a desired combo box column with next xaml code:
<DataGridComboBoxColumn x:Name="ComboBoxColumn" Header="Country" DisplayMemberPath="CountryName"
ItemsSource="{StaticResource CountriesArray}" Width="Auto"
SelectedItemBinding="{Binding CountryData, UpdateSourceTrigger=PropertyChanged}">
<DataGridComboBoxColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="ToolTip">
<Setter.Value>
<ContentControl Content="{Binding }">
<ContentControl.ContentTemplate>
<DataTemplate DataType="{x:Type soDataGridProjectsHelpAttempt:UserData}">
<DataTemplate.Resources>
<system:String x:Key="NoAnyEntriesKey">
No any entry presented
</system:String>
</DataTemplate.Resources>
<TextBlock Text="{Binding CountryData.Description, FallbackValue={StaticResource NoAnyEntriesKey}}"></TextBlock>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Setter.Value>
</Setter>
</Style>
</DataGridComboBoxColumn.CellStyle>
</DataGridComboBoxColumn>
and take in account you nedd to extend Country model with description property.
regards,