简体   繁体   中英

c# wpf combobox column in child datagrid

I am working on a WPF application with two DataGrids—one for TimeCard objects and a second for time card line (“TcLine”) objects. There is a one-to-many relationship between TimeCards and TcLines. The TimeCard datagrid is set up with a SelectionChanged event which populates the child datagrid with related TcLine records. The event works fine but I want to have this TcLine datagrid include a DataGridComboBoxColumn to allow users to change the approval status of a given line from a dropdown. So far I have not been able to get the DataGridComboBoxColumn to work. Here is the XAML:

    <Grid>
    <DataGrid x:Name="TimeCardGrid" HorizontalAlignment="Left" 
              Height="100" Margin="62,30,0,0" VerticalAlignment="Top" 
              Width="454" AutoGenerateColumns="False" 
              SelectionChanged="TimeCardGrid_SelectionChanged">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Id" Binding="{Binding EmployeeId}" 
                                Width="75"></DataGridTextColumn>
            <DataGridTextColumn Header="Week Ending" 
                                Binding="{Binding WeekEnding}" 
                                Width="*"></DataGridTextColumn>
        </DataGrid.Columns>
    </DataGrid>
    <DataGrid x:Name="TcLineGrid" HorizontalAlignment="Left" Height="154" Margin="85,207,0,0" 
              VerticalAlignment="Top" Width="431" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Job Number" 
                                Binding="{Binding JobNumber}" Width="80"/>
            <DataGridTextColumn Header="Phase Code" 
                                Binding="{Binding PhaseCode}" Width="80"/>
            <DataGridTextColumn Header="Rate Factor" 
                                Binding="{Binding RateFactor}" Width="80"/>
            <DataGridComboBoxColumn Header="Mon Approval" x:Name="MondayApproval" Width="90" 
                                    SelectedItemBinding="{Binding MondayApproval, Mode=TwoWay}" 
                                    DisplayMemberPath="{Binding MondayApproval}"/>
            <DataGridTextColumn Header="Monday" Binding="{Binding MondayHours}" Width="*"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

Here is the code behind for the main window:

    public partial class MainWindow : Window
{
    List<TimeCard> timeCards;
    List<string> approvalStatuses;
    TimeCard timeCard1;
    TimeCard timeCard2;

    public MainWindow()
    {
        InitializeComponent();
        //load timncard objects
        timeCard1 = new TimeCard(1, DateTime.Parse("1/5/2018"));
        timeCard1.TcLines.Add(new TcLine(DateTime.Parse("1/5/2018"), "941119", "009-150-", 1.0));
        timeCard1.TcLines.Add(new TcLine(DateTime.Parse("1/5/2018"), "941119", "009-150-", 1.5));
        timeCard1.TcLines.Add(new TcLine(DateTime.Parse("1/5/2018"), "941119", "009-800-", 0.0));
        timeCard2 = new TimeCard(2, DateTime.Parse("1/5/2018"));
        timeCard2.TcLines.Add(new TcLine(DateTime.Parse("1/5/2018"), "971290", "009-151-", 1.0));
        timeCard2.TcLines.Add(new TcLine(DateTime.Parse("1/5/2018"), "971290", "009-151-", 1.5));
        timeCard2.TcLines.Add(new TcLine(DateTime.Parse("1/5/2018"), "971290", "009-800-", 0.0));
        timeCards = new List<TimeCard> { timeCard1, timeCard2 };
        TimeCardGrid.ItemsSource = timeCards;
        //load approval status combobox options
        approvalStatuses = new List<string>
        {
            "Approved",
            "Unapproved"
        };
    }

    private void TimeCardGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        TcLineGrid.Items.Clear();
        object item = TimeCardGrid.SelectedItem;
        int id = int.Parse((TimeCardGrid.SelectedCells[0].Column.GetCellContent(item) as TextBlock).Text);
        DateTime weekEnding = DateTime.Parse((TimeCardGrid.SelectedCells[1].Column.GetCellContent(item) as TextBlock).Text);
        var timeCard = timeCards.Where(t => t.EmployeeId == id && t.WeekEnding == weekEnding).FirstOrDefault();
        foreach (var line in timeCard.TcLines)
        {
            TcLineGrid.Items.Add(line);
        }
        //set combobox column item source 
        MondayApproval.ItemsSource = approvalStatuses;
    }

And these are my models:

        public class TimeCard
    {
        public TimeCard() { TcLines = new List<TcLine>(); }

        public TimeCard(int employeeId, DateTime weekEnding)
        {
            EmployeeId = employeeId;
            WeekEnding = weekEnding;
            TcLines = new List<TcLine>();
        }

        public int EmployeeId { get; set; }
        public DateTime WeekEnding { get; set; }
        public List<TcLine> TcLines { get; set; }
        public double PerDiem { get; set; }
    }

    public class TcLine
    {
        public TcLine(DateTime weekEnding, string jobNumber, string phaseCode, double rateFactor)
        {
            JobNumber = jobNumber;
            PhaseCode = phaseCode;
            RateFactor = rateFactor;
            MondayHours = 0.0;
            MondayApproval = "A";
        }
        public string JobNumber { get; set; }
        public string PhaseCode { get; set; }
        public double RateFactor { get; set; }
        public double MondayHours { get; set; }
        public string MondayApproval { get; set; }
    }

}

I tried a version of this without the Time card object and grid, and the XAML for the DataGridComboBoxColumn worked fine so I'm guessing the problem has to do with my SelectionChanged event. I tried moving the assignment of this column's ItemSource property from the main window constructor into the selection changed method, but that didn't work. Has anyone had a similar problem? Sorry for the verbosity and TIA

Setting the Items directly in your SelectionChanged method prevents the DataGrid Items from being Editable. Set The ItemsSource instead. You can indeed do that in a one-liner:

    private void TimeCardGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
         TcLineGrid.ItemsSource = (TimeCardGrid.SelectedItem as TimeCard)?.TcLines;
    }

The ItemsSource for the ComboBox you can savely set in the Constructor of MainWindow.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM