0

I'm using C# (.core) and Wpf to create an application that will connect to a SQL database. I created the DB wrapper and have the datable out of the SQL database.

I haven't used WPF much but have spent the last two days looking for a solution. This is what I am trying to do (kindly refer to my sample table image bellow):

enter image description here

  1. In my WPF table, I bring in the employee data table with four columns EmployeeID, LastName, FirstName and Active.
  2. I do not want the users to edit the EmployeeID, Last Name or FirstName.
    These fields can be (preferably) read-only or disabled.
  3. The users must be able to edit the active column.
  4. The users must be able to add a new row, and when they do so they will need to add an EmployeeID, LastName, FirstName, and active.
  5. The cells that are read-only should have a background color of red.
  6. The new row should have a background color of green

I have tried setting the EmployeeID, Lastname and Firstname columns to read only in WPF, however when I do that it disables the ability to edit the EmployeeID, FirstName, and Lastname new row columns.

I have tried setting the rows read only except for new rows (.isnewrow) but then the active column would also be read only.

I have unsuccessfully tried setting some cell configurations, but that also didn't work or I did it wrong.

This can't be this hard. Can anyone help with the XAML and or C# to make the magic happen?

Thanks, Kerry

SamTh3D3v
  • 9,854
  • 3
  • 31
  • 47
Kerry
  • 57
  • 8

1 Answers1

0

One way to approach this is based on the code in this answer:

How to make WPF DataGridCell ReadOnly?

Which is switching out the template for a cell using a datatrigger.

In case that gets orphaned somehow the markup from there is:

<DataGrid>
 <DataGrid.Resources>
   <!-- the non-editing cell -->
   <DataTemplate x:Key="ReadonlyCellTemplate">
      <TextBlock Text="{Binding MyCellValue}" />
   </DataTemplate>

    <!-- the editing cell -->
    <DataTemplate x:Key="EditableCellTemplate">
     <TextBox Text="{Binding MyCellValue}" />
   </DataTemplate>
  </DataGrid.Resources>
</DataGrid>

and

    <DataGridTemplateColumn CellTemplate="{StaticResource ReadonlyCellTemplate}">
        <DataGridTemplateColumn.CellEditingTemplate>
            <DataTemplate>
                <!-- the additional layer of content presenter -->
                <ContentPresenter x:Name="Presenter" Content="{Binding}" ContentTemplate="{StaticResource ReadonlyCellTemplate}" />
                <DataTemplate.Triggers>
                    <!-- dynamically switch the content template by IsEditable binding -->
                    <DataTrigger Binding="{Binding IsEditable}" Value="True">
                        <Setter TargetName="Presenter" Property="ContentTemplate" Value="{StaticResource EditableCellTemplate}" />
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </DataGridTemplateColumn.CellEditingTemplate>
    </DataGridTemplateColumn>

You need a property to drive that Datatrigger.

Define a viewmodel which will represent each row (rowViewModel).

That needs a public property in it for each column.

Then you need your new property for that datatrigger which will show whether it's a New row or not. Call that IsNew ( or whatever you prefer ). Bind Itemssource to an observable collection of RowViewModel. The default value for IsNew should be true. When you read old data out the database set IsNew to false.

You then need to apply that approach to all columns but your last one.

Which will be pretty clunky but you only have have 4 columns total. Pasting very similar markup 3 times is inelegant but not hugely so. Once you get it working that way you can consider whether you want to refactor and neaten it up.

Another option is to use two datagrids. Put one underneath the other in a stackpanel. Hide the headers on the second one. Use that only to do inserts.

You then don't have your edit new row in the same datagrid so all it's columns can be regular columns. The top one has readonly columns.

If the user can resize column width using the headers on the top datagrid you need to bind the column widths so they don't get out of step.

A third option. Insert using an entirely separate panel rather than jn a datagrid. I don't usually allow users to edit in a datagrid at all since it's harder to validate that way and users can have a tendency to think this is just an excel sort of experience rather than serious business data. I use an overlay panel along the lines of this. https://social.technet.microsoft.com/wiki/contents/articles/29777.wpf-property-list-editing.aspx The user either clicks an insert button or selects a row in the datagrid and clicks an edit button.

Andy
  • 11,864
  • 2
  • 17
  • 20
  • I think I'm coming to the: "Another option is to use two datagrids. Put one underneath the other in a stackpanel. Hide the headers on the second one. Use that only to do inserts." as the most effective option. I was really hoping there was a much more elegant option in WPF. – Kerry Nov 01 '19 at 17:03
  • @Kerry i added a third option which might be worth considering but isn't quite what you asked for. – Andy Nov 01 '19 at 18:21