1

I have a WPF window with a grid (named SimOrder_grd) that is built into my MainWindow that is filled with buttons inside my MainWindow_Loaded event as follows:

public partial class MainWindow: Window
{
   List<DirectiveObjects> SimOrders = new List<DirectiveObjects>();
    SqlConnection admin_connect = ... (removed for post)
    public MainWindow()
    {
        InitializeComponenent();
        Loaded += MainWindow_Loaded;
    }
    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        admin_connect.Open();
        string sim_sqlString = "SELECT * FROM dbo.SimOrder;";
//get all sim orders from database
        using (SqlCommand so_cmd = new SqlCommand(sim_sqlString,admin_connect))
        {
            SqlDataReader so_rd = so_cmd.ExecuteReader();
            while (so_rd.Read())
            {
                 SimOrders.Add(new DirectiveObjects 
                       {
                           id= Convert.ToInt16(so_rd["Id"]),
                           title = so_rd["Title"].ToString(),
                       });
             }
         }
         admin_connect.Close();
         int topmargin = 0; int rownum = 0;
         foreach(DirectiveObjects dir in SimOrders)
         {
             //generate button
             Button dir_btn = new Button();
             dir_btn.Content = dir.title; dir_btn.Width = SimOrder_grd.Width;
             dir_bt.Height = 20;
             dir_btn.Margin = new Thickness(0, topmargin, 0,0);
             dir_btn.Name = dir.title + "_btn";
             dir_btn.Click += dir_btn_Click;
             SimOrder_grd.Children.Add(dir_btn); topmargin += 25; rownum++;
          }
        }

This all works as expected, and I get a nice button inside of my grid that I can click on; dir_btn_click event works fine. However, I've created a button where users can add there own "SimOrder" to the grid menu. It is called AddSimO and the button click works below:

private void AddSimO_btn_Click(object sender, RoutedEventArgs e)
{
    string DBName = "dbo.SimOrder"; string GridName = "SimOrder_grd";
    var CreateNewDialog = new FrAdministration.SimAdd(DBName, GridName);
    CreateNewDialog.Show();
 }

This opens a new window that the user can type in a new title for a sim order, it get's saved to the database like so. From SimAdd.xaml.cs;

public partial class SimAdd: Window
{
    public SimAdd(string db, string grid)
    {
        InitializeComponent();
    }
    private void Cancel_btn_Click(object sender, RoutedEventArgs e)
    {
        this.Close(); //cancel button closes the window.
    }
    private void saveSim_btn_Click(object sender, RoutedEventArgs e)
    {
        if (String.IsNullOrEmpty(SimName_txt.Text){MessageBox.Show("Please enter a title");}
        else
        {
            SqlConnection Si_connect = new ...(removed again)
            Si_connect.Open();
            string add_sqlString = "INSERT INTO dbo.SimOrder (Title) VALUES (@title);";
            using (SqlCommand add_cmd = new SqlCommand(add_sqlString, SimConnect))
            {
                add_cmd.Parameters.Add("@title", SqlDbType.NvarChar).Value = SimName_txt.Text;
                add_cmd.ExecuteNonQuery();
             }
             Si_connect.Close();
             this.Close();
             MainWindow mwindow = new FrAdministration.MainWindow();
             mwindow.Sim_update();
        }
    }
}

This works as well as I can see my database update. The next piece is where my question lies.

How can I get my grid to update with the new button for the new entry I've created in my database. Here is what I've tried:

1.) I tried to recreate my button list inside of the Sim_update method called in the SimAdd window.

public void Sim_update()
{
    admin_connect.Open();
    SimOrder_grd.Children.Clear(); SimOrders.Clear();
    this.UpdateLayout();//saw this on Stack Overflow and thought I'd try.
        string sim_sqlString = "SELECT * FROM dbo.SimOrder;";
//get all sim orders from database
        using (SqlCommand so_cmd = new SqlCommand(sim_sqlString,admin_connect))
        {
            SqlDataReader so_rd = so_cmd.ExecuteReader();
            while (so_rd.Read())
            {
                 SimOrders.Add(new DirectiveObjects 
                       {
                           id= Convert.ToInt16(so_rd["Id"]),
                           title = so_rd["Title"].ToString(),
                       });
             }
         }
         admin_connect.Close();
         int topmargin = 0; int rownum = 0;
         foreach(DirectiveObjects dir in SimOrders)
         {
             //generate button
             Button dir_btn = new Button();
             dir_btn.Content = dir.title; dir_btn.Width = SimOrder_grd.Width;
             dir_bt.Height = 20;
             dir_btn.Margin = new Thickness(0, topmargin, 0,0);
             dir_btn.Name = dir.title + "_btn";
             dir_btn.Click += dir_btn_Click;
             SimOrder_grd.Children.Add(dir_btn); topmargin += 25; rownum++;
          }
        }

I understand this is the same information that was in MainWindow_Loaded event, but this wouldn't work.

2.) I tried adding this.UpdateLayout(); and this.InvalidateVisual() after my foreach loop and after my grid clearing, but that didn't seem to help. I also tried SimOrder_grd.UpdateLayout(); and SimOrder_grd.InvalidateVisual();.

3.) I created a button to refresh my page called Refresh. This works to refresh my grid when I manually click the button.

private void Refresh_Click(object sender, RoutedEventArgs e)
{
    admin_connect.Open();
    SimOrder_grd.Children.Clear(); SimOrders.Clear();
    this.UpdateLayout();
    string sim_sqlString = "SELECT * FROM dbo.SimOrder;";
//get all sim orders from database
        using (SqlCommand so_cmd = new SqlCommand(sim_sqlString,admin_connect))
        {
            SqlDataReader so_rd = so_cmd.ExecuteReader();
            while (so_rd.Read())
            {
                 SimOrders.Add(new DirectiveObjects 
                       {
                           id= Convert.ToInt16(so_rd["Id"]),
                           title = so_rd["Title"].ToString(),
                       });
             }
         }
         admin_connect.Close();
         int topmargin = 0; int rownum = 0;
         foreach(DirectiveObjects dir in SimOrders)
         {
             //generate button
             Button dir_btn = new Button();
             dir_btn.Content = dir.title; dir_btn.Width = SimOrder_grd.Width;
             dir_bt.Height = 20;
             dir_btn.Margin = new Thickness(0, topmargin, 0,0);
             dir_btn.Name = dir.title + "_btn";
             dir_btn.Click += dir_btn_Click;
             SimOrder_grd.Children.Add(dir_btn); topmargin += 25; rownum++;
          }
        }

I don't want the users to have to click another button to see their changes, so I tried to automate the button in the following ways (all inside of Sim_update from the 4th code quote block).

4.) ButtonAutomationPeer peer = new ButtonAutomationPeer(Refresh); IInvokeProvider invoker = peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider; invoker.Invoke();

5.) Refresh.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));

6.) Refresh.Click(this,null);

Both of these will run the Refresh_Click event, but neither updates the grid like manually pressing the Refresh button.

Lastly I tried the following inside Sim_update(): 7.)

this.Dispatcher.BeginInvoke(new Action() => this.SimOrder_grd.UpdateLayout()), null);

and 8.) Action EmptyDelegate = delegate(){}; SimOrder_grd.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);

I am all out of ideas, and I would really like to know functionally why everything I'm trying is not working.

Is it because I'm coming from a second window and running method without activating the main window?

Is it because ButtonAutomationPeer does not update the UI the same as manually clicking the button?

Thank you all,

pyathalon
  • 21
  • 5
  • 1
    Maybe you can use an Observable Collection as ItemSource in the grid so you can get the changes in the two windows without refresh. – ganchito55 Mar 24 '16 at 00:13
  • I've seen a lot of posts about people creating Datagrids in this way, but do you know if I can bind buttons to a data grid. That's really the reason I didn't pursue using that in the beginning. – pyathalon Mar 24 '16 at 00:17
  • You can put a button inside a datagrid with custom template, you can also use an event like SourceChanged, you raise that event in the second window and you catch it in the first window and refresh the data. – ganchito55 Mar 24 '16 at 00:21
  • I think that's what I may do. I keep forgetting that with wpf, you can click on almost anything that you know the position of with all the mouse events they have available. I probably don't even need buttons to do the types of things I'm looking for. So much time wasted... – pyathalon Mar 24 '16 at 00:24
  • @pyathalon: You pretty much *never* need to create any UI elements in code in WPF. If you do, you are probably doing it wrong. Regarding buttons, [here's how one binds them](http://stackoverflow.com/a/5930121/546730). And as noted by gachito55, you can use a `DataGridTemplateColumn` to create a template with a button in a `DataGrid`. – H.B. Mar 24 '16 at 04:57

0 Answers0