Reputation: 125
I have found this : How to show a loading graphic/animation when wpf data binding is taking place
But don't understand how to apply it for my work.
I have My MainWindow. It call all my user controls in it.
On a user control, I have a DataGrid. after press "Go" button, the datagrid load data from MySQL. It take a long time to do and I want to show a dialog window with "Please Wait" during the loading of the datagrig.
I have found the link below but don't understant how to call it correctly.
Do I need to put this "loader" in a new class file like "Loader.cs" andthe button call it ? Ok but how to close it when datagrid is finished ?
I'm lost... Well if an other solution exist and simply to use...
Thanks by advance
EDIT TEST 1 :
Tried an simple test with slider to get a time to wait and a button.
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace TEST_LoadingPage
{
/// <summary>
/// Logique d'interaction pour MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btnTester_Click(object sender, RoutedEventArgs e)
{
Window waitWindow = new Window { Height = 100, Width = 200, WindowStartupLocation = WindowStartupLocation.CenterScreen, WindowStyle = WindowStyle.None };
waitWindow.Content = new TextBlock { Text = "Veuillez patienter...", FontSize = 30, HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center };
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
Dispatcher.BeginInvoke(new Action(delegate { waitWindow.ShowDialog(); }));
lbReussite.Visibility = Loop.Pause(slider.Value);
Dispatcher.BeginInvoke(new Action(delegate() { waitWindow.Close(); }));
};
worker.RunWorkerAsync();
}
}
public class Loop
{
public static System.Windows.Visibility Pause(double duree)
{
try
{
DateTime begin = new DateTime();
DateTime end = new DateTime();
int i = 0;
begin = DateTime.Now;
end = DateTime.Now.AddSeconds(duree);
while (DateTime.Now <= end)
i++;
return System.Windows.Visibility.Visible;
}
catch (Exception)
{
return System.Windows.Visibility.Hidden;
}
}
}
}
but don't work with error :
The calling thread can not access this object because a different thread owns it
I know its a courant error but I don't see "DispatcherTimer" or else that I've seen before in precedent project... So I'll try the second code tomorrow BUT. I don't understand where i put my method :(
EDIT 2
I tried with your code... I'm too stupide maybe.
I've write the class in a Loader.cs and in my MainWiondow (its a test)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btnTester_Click(object sender, RoutedEventArgs e)
{
Loader<List<Donnees>> loader = new Loader<List<Donnees>>(GenerateList((int)slider.Value);
loader.JobFinished += new Loader<Donnees>.OnJobFinished(loader_JobFinished);
loader.Load();
}
private List<Donnees> GenerateList(int number)
{
List<Donnees> list = new List<Donnees>();
for (int i = 1; i <= number; i++)
{
Donnees data = new Donnees();
data.Id = i;
data.Name = "Ligne " + i;
list.Add(data);
}
return list;
}
void loader_JobFinished(object sender, List<Donnees> result)
{
result = GenerateList((int)slider.Value);
dgDataGrid.ItemsSource = result;
}
}
public class Donnees
{
#region Properties
private int id;
public int Id
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
#endregion
public Donnees()
{
id = -1;
name = "";
}
}
Upvotes: 1
Views: 6226
Reputation: 6014
You put the following code in a method in the code-behind of your DataGrid-UserControl which gets called in your button-click-eventhandler:
Window waitWindow = new Window { Height = 100, Width = 200, WindowStartupLocation = WindowStartupLocation.CenterScreen, WindowStyle = WindowStyle.None };
waitWindow.Content = new TextBlock { Text = "Please Wait", FontSize = 30, FontWeight = FontWeights.Bold, HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center };
Now you can decide...
...if you want to create a DataLoader-class, which loads the data and fires an DataLoaded event when completed, than add:
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
Dispatcher.BeginInvoke(new Action(delegate { waitWindow.ShowDialog(); }));
DataLoader dataLoader = new DataLoader();
dataLoader.DataLoaded += delegate
{
Dispatcher.BeginInvoke(new Action(delegate() { waitWindow.Close(); }));
};
dataLoader.LoadData();
};
worker.RunWorkerAsync();
... or if you just copy your data-loading-code into this method and add:
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
Dispatcher.BeginInvoke(new Action(delegate { waitWindow.ShowDialog(); }));
//do dataloading here
Dispatcher.BeginInvoke(new Action(delegate() { waitWindow.Close(); }));
};
worker.RunWorkerAsync();
EDIT: I wrote a class, which should do what you want without much code in the code-behind:
public class Loader<TFuncResult,TFirstArgType>:FrameworkElement
{
private Func<TFirstArgType,TFuncResult> _execute;
public TFuncResult Result { get; private set; }
public delegate void OnJobFinished(object sender, TFuncResult result);
public event OnJobFinished JobFinished;
public Loader(Func<TFirstArgType,TFuncResult> execute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
}
private Window GetWaitWindow()
{
Window waitWindow = new Window { Height = 100, Width = 200, WindowStartupLocation = WindowStartupLocation.CenterScreen, WindowStyle = WindowStyle.None };
waitWindow.Content = new TextBlock { Text = "Please Wait", FontSize = 30, FontWeight = FontWeights.Bold, HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center };
return waitWindow;
}
public void Load(TFirstArgType firstarg, Window waitWindow = null)
{
if (waitWindow == null)
{
waitWindow = GetWaitWindow();
}
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
Dispatcher.BeginInvoke(new Action(delegate { waitWindow.ShowDialog(); }));
Result = _execute(firstarg);
Dispatcher.BeginInvoke(new Action(delegate() { waitWindow.Close(); }));
};
worker.RunWorkerCompleted += delegate
{
worker.Dispose();
if (JobFinished != null)
{
JobFinished(this, Result);
}
};
worker.RunWorkerAsync();
}
}
EDIT 2: How to use it:
Lets say your GenerateList()
returns Data of Type List<Donnees>
and the arguments Type is of Type int
(works with all Types):
Place this where you want to load the Data (e.g. in your Window_Loaded-Event):
Loader<List<Donnees>, int> loader = new Loader<List<Donnees>, int>(GenerateList);
loader.JobFinished += new Loader<List<Donnees>, int>.OnJobFinished(loader_JobFinished);
loader.Load((int)slider.Value);
Now call this EventHandler in the Code-Behind:
void loader_JobFinished(object sender, List<Donnees> result)
{
YourDataGrid.DataSource = result
}
Upvotes: 2