2

I need help to finish my first little app. I'm trying to do action for checked's rows in a datagrid.

the xaml :

                <DataGrid x:Name="dgConnected_Users" AutoGenerateColumns="False" IsReadOnly="True" Height="180" Background="Azure" ScrollViewer.CanContentScroll="True" FontSize="11" BorderBrush="#26BFF0" ScrollViewer.HorizontalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled" BorderThickness="2,2,2,2" HeadersVisibility="Column" CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="False" RowHeight="20" RowBackground="Azure" GridLinesVisibility="Horizontal" HorizontalGridLinesBrush="DarkOrange" Margin="10,0,10,0">
                <DataGrid.Columns>
                    <DataGridTextColumn x:Name="UID_UserName" FontFamily="Segoe UI Bold" Binding="{Binding UID_UserName}" Header="Utilisateur" Width="1*">
                        <DataGridTextColumn.ElementStyle>
                            <Style TargetType="TextBlock">
                                <Setter Property="VerticalAlignment" Value="Center"></Setter>
                                <Setter Property="Margin" Value="5,0"></Setter>
                            </Style>
                        </DataGridTextColumn.ElementStyle>
                    </DataGridTextColumn>
                    <DataGridTextColumn x:Name="UID_ComputerName" Binding="{Binding UID_ComputerName}" Header="Machine" Width="1*">
                        <DataGridTextColumn.ElementStyle>
                            <Style TargetType="TextBlock">
                                <Setter Property="VerticalAlignment" Value="Center"></Setter>
                                <Setter Property="Margin" Value="5,0"></Setter>
                            </Style>
                        </DataGridTextColumn.ElementStyle>
                    </DataGridTextColumn>
                    <DataGridTemplateColumn x:Name="UID_Chkbox" Width="24">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock TextAlignment="Center" VerticalAlignment="Center"><CheckBox x:Name="Chk_UID_IsSelected" IsChecked="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Checked="Chk_UID_IsSelected_Checked" Unchecked="Chk_UID_IsSelected_Unchecked" Click="Chk_UID_IsSelected_Click"/></TextBlock>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                        <DataGridTemplateColumn.Header>
                            <Image Source="components/resources/images/delete-24.png" Height="12" Width="12" StretchDirection="Both" Stretch="Fill"/>
                        </DataGridTemplateColumn.Header>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
            <StackPanel Margin="10,10">
                <Button x:Name="UID_Disconnect" Width="270" Click="UID_Disconnect_Click">Déconnecter le(s) utilisateur(s)</Button>
            </StackPanel>
            <StackPanel Margin="10,0">
                <Grid>
                    <Border BorderBrush="#26BFF0" BorderThickness="0,1,0,0">
                        <TextBlock HorizontalAlignment="Center" FontFamily="Segoe UI Light" FontSize="10" Padding="5" Foreground="#FF4C4F54">InovaGes SAS · Développé par Fabrice BERTRAND</TextBlock>
                    </Border>
                </Grid>
            </StackPanel>

The xaml.cs :

    private void UID_Disconnect_Click(object sender, RoutedEventArgs e)
    {
        /// gestion de la déconnexion des utilisateurs au clic du bouton 'UID_Disconnect'
        /// 
        IEnumerable<CheckBox> UsersInDatabase = dgConnected_Users.Items.OfType<CheckBox>().Where(usr => usr.IsChecked == true);

        foreach (CheckBox usr in UsersInDatabase)
        {

            MessageBox.Show("yeah"); /// do stuff here
        }
    }

I'm testing the code with a MessageBox for now. But nothing happen. An idea to help me to finish my project ?

In fact, I need for each row where checkbox is checked to get the UID_UserName to do a sql delete.

I have tried with DataRowView too. I can get TextColumn but nothing with checkbox.

Edit 1 :

I think a part of the problem is due that the column with checkbox is not in the dt :

        private void refresh_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            if (Cnx.State == System.Data.ConnectionState.Open)
            {
                Cnx.Close();
            }
            if (cmbAuthentification.Text.Equals("Windows"))
            {
                SQL_Connection.ConnectionString = @"Server = " + txtServerName.Text + "; Integrated Security = SSPI;";
                Cnx.ConnectionString = SQL_Connection.ConnectionString;
            }
            else if (cmbAuthentification.Text.Equals("SQL Server"))
            {
                SQL_Connection.ConnectionString = @"Server = " + txtServerName.Text + "; User ID =" + txtUserID.Text + "; Password=" + txtUserPwd.Password + ";";
                Cnx.ConnectionString = SQL_Connection.ConnectionString;
            }
            Cnx.Open();
            Cmd.Connection = Cnx;
            Cmd.CommandText = ("USE \"" + cmbDatabase.Text + "\";SELECT DISTINCT b.nt_username AS [UID_UserName], b.hostname AS [UID_ComputerName] FROM cbUserSession a INNER JOIN master..sysprocesses b ON a.cbSession = b.spid WHERE a.cbUserName IS NOT NULL;");
            SqlDataAdapter da = new SqlDataAdapter(Cmd);
            dt = new DataTable("Connected_Users");
            da.Fill(dt);
            /// dt.Columns.Add(new DataColumn("IsChecked", typeof(bool))); <-- maybe need to do something like that ?
            dgConnected_Users.ItemsSource = dt.DefaultView;
            Cnx.Close();
        }
        catch (Exception exception)
        {
            MessageBox.Show("Erreur de chargement des données pour le motif suivant : \n" + exception.Message, "OOoopssss !!!", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }

1 Answer 1

3

I had constructed the rest of the code in order to show you the working copy.

I assume you have a class object which you are binding as an items source to data-grid. FYI, I have created my own class object. See below and change as per your class file.

Step 1 - Class creation

public class DataGridUser
{
    public string UID_UserName { get; set; }

    public string UID_ComputerName { get; set; }

    public bool IsChecked { get; set; }
}

Step 2 - On button click, I just modified the code as below.

private void UID_Disconnect_OnClick(object sender, RoutedEventArgs e)
    {
        var selectedItems = dgConnected_Users.Items.Cast<DataGridUser>().Where(x => x.IsChecked);

        foreach (var item in selectedItems)
        {
            MessageBox.Show(item.UID_ComputerName + " " + item.UID_UserName);
        }
    }

In above code, I have used the "Cast" type and casting the item to the type that data grid is bound to which is DataGridUser (in this case).

Rest of the code is same as yours.

Edit Added code to answer your comment.

Step 3 I have copied your event handler and then made slight change. Please compare the code and read comments carefully and then use it in your program.

private void refresh_Click(object sender, RoutedEventArgs e)
{
    try
    {
        if (Cnx.State == System.Data.ConnectionState.Open)
        {
            Cnx.Close();
        }
        if (cmbAuthentification.Text.Equals("Windows"))
        {
            SQL_Connection.ConnectionString = @"Server = " + txtServerName.Text + "; Integrated Security = SSPI;";
            Cnx.ConnectionString = SQL_Connection.ConnectionString;
        }
        else if (cmbAuthentification.Text.Equals("SQL Server"))
        {
            SQL_Connection.ConnectionString = @"Server = " + txtServerName.Text + "; User ID =" + txtUserID.Text + "; Password=" + txtUserPwd.Password + ";";
            Cnx.ConnectionString = SQL_Connection.ConnectionString;
        }
        Cnx.Open();
        Cmd.Connection = Cnx;
        Cmd.CommandText = ("USE \"" + cmbDatabase.Text + "\";SELECT DISTINCT b.nt_username AS [UID_UserName], b.hostname AS [UID_ComputerName] FROM cbUserSession a INNER JOIN master..sysprocesses b ON a.cbSession = b.spid WHERE a.cbUserName IS NOT NULL;");
        
        //SqlDataAdapter da = new SqlDataAdapter(Cmd);
        //dt = new DataTable("Connected_Users");
        //da.Fill(dt);
        // dt.Columns.Add(new DataColumn("IsChecked", typeof(bool))); <-- maybe need to do something like that ?

        // GK - Instead of using SqlDataAdapter. Use DataReader and transfer the data from DataReader to an object. See below.
            SqlDataReader reader = Cmd.ExecuteReader();
            var dataGridUserCollection = new List<DataGridUser>();

            if (reader.HasRows)
            {
                while (reader.Read())
                {
                    var currentDataGridUser = new DataGridUser()
                    {
                        UID_UserName = reader["UID_UserName"].ToString(),
                        UID_ComputerName = reader["UID_ComputerName"].ToString()
                    };

                    dataGridUserCollection.Add(currentDataGridUser);
                }
            }

            // GK - Bind new list object to DataGrid.
            // GK - Now the object bound to DataGrid is of type DataGridUser.
            // GK - So now when you do the type casting to DataGridUser on your button click
            // it won't throw any more error.

            //dgConnected_Users.ItemsSource = dt.DefaultView;
            dgConnected_Users.ItemsSource = dataGridUserCollection; 
            
        Cnx.Close();
    }
    catch (Exception exception)
    {
        MessageBox.Show("Erreur de chargement des données pour le motif suivant : \n" + exception.Message, "OOoopssss !!!", MessageBoxButton.OK, MessageBoxImage.Error);
    }
}

Note:- I assume that the columns are of type string and then converting them to a string. You should take care of this minimum things before you run your code.

Let us know in case if you still face any problems.

Sign up to request clarification or add additional context in comments.

5 Comments

thanks for our answer. I have try our code, but something goes wrong. Like some other try, the app crash when I click on the disconnect button.
event windows viewer : Exception Info: System.InvalidCastException: Unable to cast object of type 'System.Data.DataRowView' to type 'dgUsersInDatabase'.
From your edited question, I could see that you are binding a DataTable to data-grid and in that case when we are type casting to an object (DataGridUser in this case) causing the app to be crashed because of invalid cast exception. What you can do otherwise is to create a class like I stated in my answer and then fill data to the object instead of data-table and then bind the object (collection) to data-grid. This is simple and good practice though. Give a try and let us know.
Hi, do you have an exemple to do that ? I'm trying to search, but find nothing about that. Maybe I don't search with good terms.
+1 U are my new god ! 1 week I try to find a way and splash, so easy for u ! I'm sure my code is so poor :-( Next level, need to optimize the size of the app to render it the most portable as possible

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.