Jeremy Jordan
Jeremy Jordan

Reputation: 31

How to highlight a row and force row/cell refresh in a WPF DataGrid?

This is my first question on SOF, so please be gentle on me :)

I have a simple WPF DataGrid defined in XAML. The application loads "user" data (FirstName, LastName) into the grid from a text file, and after loading the entries from a text file, the user hit the submit button, I want to iterate over the items in the list and submit each row to a webservice that creates Users and then display the reply from the webservice in the grid.

In order to keep the user informed, I want to somehow highlight the current row being submitted, and I want the message to appear immediatly after the response is received. If the message is an error, highlight the row in red, if success, highlight it in green.

Seems simple enough...

I have a simple GridDto class that represents the Data to map to each row. It implements the INotifyPropertyChanged interface. For simplicity sake, I define it as following:

class GridDto : INotifyPropertyChanged
{
  public string FirstName { get; set; }
  public string LastName { get; set; }

  private string Reply;
  public string Reply
  {
      get
      {
        return this.message;
      }
      set
      {
          this.message = value;
          this.PropertyChanged(this, new PropertyChangedEventArgs("Reply"));
      }
   }

The grid accepts a list of FirstName and LastNames from a text file.

The way I populate this grid is to build a collection of ObservableCollection<GridDto> and then I do:

resultGrid.ItemsSource = ConvertTextDtoToGridDtos(result.Elements);

So far so good. Now I want to submit each of the rows of my grid to a webservice that create Users. The only parameters the websrvice requires is FirstName and LastName.

Since I am new to WPF, I have no idea on how to do that. Here is what I did so far:

for (int i = 0; i < resultGrid.Items.Count - 1; i++)
{
    var dto = (GridDto)this.resultGrid.Items[i];
    var color = Color.FromRgb(192, 192, 25);
    try{
       // Do webservice call using the dto data
    }
    catch(Exception ex){
      dto.Reply = ex.Message;
      color = Color.FromRgb(255, 0, 0);
    }

  DataGridRow row = (DataGridRow)resultGrid.ItemContainerGenerator.ContainerFromIndex(i);
  row.Background = new SolidColorBrush(color) { Opacity = 0.45 };
}

This somewhat works, but doesn't highlight the row being treated currently.

I tried adding the following in my loop

resultGrid.SelectedIndex = i;

Or...

resultGrid.SelectedItem = resultGrid.Items[i];
resultGrid.ScrollIntoView(resultGrid.Items[i]);

And only the last row is highlighted at the end of the loop, when everything seems to be updated.

The other problem with this code is that the Reply column only gets refreshed at the end, after all the rows have been submitted, so there is no realtime informing the user.

How do I highlight in a smart way the row currently treated, and most importantly, how do I update the reply cell after every reply, and before processing the next row.

Thanks for your help, and sorry for my long question.

Edit: if there is a better way of doing this all together, I am opened for suggestions.

Upvotes: 3

Views: 3669

Answers (2)

Silvermind
Silvermind

Reputation: 5944

This could be an option:

Add the following to GridDto

private Brush validationBrush = Brushes.White;

public Brush ValidationBrush
{
  get { return validationBrush; }
  set
  {
    validationBrush = value;
     this.PropertyChanged(this, new PropertyChangedEventArgs("ValidationBrush"));
  }
}

And this to within your DataGrid Tag in Xaml

  <DataGrid.Resources>
    <Style TargetType="{x:Type DataGridRow}">
      <Setter Property="Background" Value="{Binding Path=ValidationBrush}"/>
    </Style>
  </DataGrid.Resources>

Updating the ValidationBrush on a GridDto item will change the RowColor

Edit

Could this be usefull:

var MyGridDtoCollection = ConvertTextDtoToGridDtos(result.Elements);
resultGrid.ItemsSource = MyGridDtoCollection;

Action a = ( ) =>
{
  foreach ( var gridDto in MyGridDtoCollection )
  {
    gridDto.ValidationBrush = Brushes.Black;
    System.Threading.Thread.Sleep( 500 );
  }
};
a.BeginInvoke( result =>
{
  a.EndInvoke( result );
} , null );

Upvotes: 0

&#214;zg&#252;r Kara
&#214;zg&#252;r Kara

Reputation: 1333

First of all you can bind bacgroundcolor to a property in style by placing this code to your XAML in DataGrid block

        <DataGrid.RowStyle>
            <Style TargetType="DataGridRow">
                <Setter Property="Background" Value="{Binding Path=Color}"/>
            </Style>
        </DataGrid.RowStyle>

if you want to refresh UI on realtime you must use backgroud worker for submiting users

            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += delegate(object s, DoWorkEventArgs we)
            {
                for (int i = 0; i < resultGrid.Items.Count - 1; i++)
                {
                    var dto = (GridDto)this.resultGrid.Items[i];
                    var color = Color.FromRgb(192, 192, 25);
                    try
                    {
                        // Do webservice call using the dto data
                    }
                    catch (Exception ex)
                    {
                        dto.Reply = ex.Message;
                        color = Color.FromRgb(255, 0, 0);
                    }
                    dto.Color = new SolidColorBrush(color) { Opacity = 0.45 };
                }
            };
            bw.RunWorkerAsync();

Upvotes: 2

Related Questions