Modal dialog like system MessageBox in Windows Phone - c#

I would like to make my own class for setting some values in dialog box in the way that MessageBox.Show() does.
My code is:
MainPage.xaml.cs
using System;
using System.Windows;
using Microsoft.Phone.Controls;
namespace ModalWindow
{
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
string result = MyModalBox.GiveMeValue();
MessageBox.Show(result);
}
}
}
MyModalBox.cs
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
namespace ModalWindow
{
public class MyModalBox
{
private static Popup modalBox;
public static string GiveMeValue()
{
TextBox textBox = new TextBox();
textBox.Width = 300;
textBox.Height = 100;
Button okButton = new Button();
okButton.Click += okButton_Click;
okButton.Content = "ok";
okButton.Width = 300;
okButton.Height = 100;
StackPanel stack = new StackPanel();
stack.Background = new SolidColorBrush(Colors.Black);
stack.Width = Application.Current.Host.Content.ActualWidth;
stack.Height = Application.Current.Host.Content.ActualHeight;
stack.HorizontalAlignment = HorizontalAlignment.Center;
stack.VerticalAlignment = VerticalAlignment.Center;
stack.Children.Add(textBox);
stack.Children.Add(okButton);
modalBox = new Popup();
modalBox.Child = stack;
modalBox.IsOpen = true;
// how to change my code to return value only after okButton is cklicked?
return textBox.Text;
}
static void okButton_Click(object sender, RoutedEventArgs e)
{
modalBox.IsOpen = false;
}
}
}
Of course it shows no result befor popup appears. How can I change my code to return value onli after clicking button? Is it possible?
Thanks in advance!

You can use TaskComplectionSource for that.
Add this:
public class DialogResult<T>
{
private readonly T _result;
private readonly bool _canceled;
public DialogResult(bool isCanceled)
: this(string.Empty, isCanceled)
{
}
public DialogResult(string result, bool canceled = false)
{
_result = result;
_canceled = canceled;
}
public T GetResults()
{
if (HasDialogBeenCanceled())
throw new InvalidOperationException("Dialog has been canceled - no results");
return _result;
}
public bool HasDialogBeenCanceled()
{
return _canceled;
}
}
// inside your dialog control
private TaskCompletionSource<DialogResult<string>> dialogResultAwaiter;
private Button button;
private TextBlock textBox;
private Popup popup;
public async Task<DialogResult<string>> ShowPopup()
{
dialogResultAwaiter = new TaskCompletionSource<DialogResult<string>>();
button.Tapped += (sender, args) => dialogResultAwaiter.SetResult(new DialogResult<string>(textBox.Text, false));
var popup = new Popup();
popup.Closed += PopupOnClosed;
// popup code
popup.IsOpen = true;
return await dialogResultAwaiter.Task;
}
private void PopupOnClosed(object sender, object o)
{
if (dialogResultAwaiter.Task.IsCompleted)
return;
dialogResultAwaiter.SetResult(new DialogResult<string>(true));
}
In this way you can create your "own await" - which will "end" (and return results) when TaskComplectionSource.SetResult is called.

Related

C# ApplyTheme method to work on all forms simultaneously

I'm trying to implement a theme changer to my app. So far I've done this:
BaseForm - has all the functions to be inherited from, it's a lengthy one so if required I'll post it here. What troubles I'm having is as follows:
MainForm has a button to open UserSettings where the user can change the theme. Problem is, I managed to get it down that the theme applies, but only for the UserSettings window, and I want it to apply to anything that is open (if there is anything else).
Edit: adding more code
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Text;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Windows.Forms;
using IniParser;
using ME___Tooling_Designer_App.Properties;
namespace ME___Tooling_Designer_App.Configuration;
public partial class UserSettings : BaseForm
{
public UserSettings()
{
InitializeComponent();
ApplyTheme();
ReadConfiguration();
}
// this is where the theme should be applied upon close
private void CBoxTheme_DropDownClosed(object sender, EventArgs e)
{
var parser = new FileIniDataParser();
var data = parser.ReadFile(_filePathSettings);
if (cBoxTheme.SelectedIndex == 0)
{
data["User_Settings"]["Theme"] = "Dark";
parser.WriteFile(_filePathSettings, data);
GlobalTheme = Enumerators.Theme.Dark;
}
if (cBoxTheme.SelectedIndex == 1)
{
data["User_Settings"]["Theme"] = "Light";
parser.WriteFile(_filePathSettings, data);
GlobalTheme = Enumerators.Theme.Light;
}
ApplyTheme();
}
public override void ApplyThemeSpecific(ThemeSettings settings)
{
panel1.BackColor = settings.PrimaryColor;
label2.ForeColor = settings.PrimaryFontColor;
btnExit.BackColor = settings.PrimaryColor;
btnExit.ForeColor = settings.PrimaryFontColor;
groupBox1.ForeColor = settings.PrimaryFontColor;
groupBox2.ForeColor = settings.PrimaryFontColor;
panel2.BackColor = settings.SecondaryColor;
}
Edit: this is BaseForm code:
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Text;
using System.Windows.Forms;
namespace ME___Tooling_Designer_App.Configuration;
public class BaseForm : Form
{
public static List<PrivateFontCollection> FontCollections;
public static Enumerators.Theme GlobalTheme { get; set; }
public void ApplyTheme()
{
var settings = new ThemeSettings();
if (GlobalTheme == Enumerators.Theme.Dark)
{
settings.PrimaryColor = Color.FromArgb(32, 30, 50);
settings.SecondaryColor = Color.FromArgb(32, 30, 45);
settings.TertiaryColor = Color.FromArgb(11, 7, 17);
settings.QuaternaryColor = Color.FromArgb(23, 21, 32);
settings.QuinaryColor = Color.FromArgb(35, 32, 39);
settings.SenaryColor = Color.LightGray;
settings.SeptenaryColor = Color.Gainsboro;
settings.PrimaryFontColor = Color.Gainsboro;
}
else if (GlobalTheme == Enumerators.Theme.Light)
{
settings.PrimaryColor = Color.LightGray;
settings.SecondaryColor = Color.GhostWhite;
settings.TertiaryColor = Color.Gainsboro;
settings.QuaternaryColor = Color.DarkGray;
settings.QuinaryColor = Color.Silver;
settings.SenaryColor = Color.Gray;
settings.SeptenaryColor = Color.Black;
settings.PrimaryFontColor = Color.Black;
}
ApplyThemeSpecific(settings);
}
public virtual void ApplyThemeSpecific(ThemeSettings settings)
{
}
}
public class Enumerators
{
public enum Theme
{
NotSet,
Light,
Dark
}
}
public class ThemeSettings
{
public Color PrimaryColor { get; set; }
public Color SecondaryColor { get; set; }
public Color TertiaryColor { get; set; }
public Color QuaternaryColor { get; set; }
public Color QuinaryColor { get; set; }
public Color SenaryColor { get; set; }
public Color SeptenaryColor { get; set; }
public Color PrimaryFontColor { get; set; }
}
this is my Program.cs:
using System;
using System.Windows.Forms;
using IniParser;
using ME___Tooling_Designer_App.Configuration;
using ME___Tooling_Designer_App.Forms;
namespace ME___Tooling_Designer_App
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
var parser = new FileIniDataParser();
var data = parser.ReadFile(Application.StartupPath + #"\" + "Config" + #"\" + "settings.ini");
var themeSetting = data["User_Settings"]["Theme"];
Application.EnableVisualStyles();
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.SetCompatibleTextRenderingDefault(false);
if (themeSetting == "Light")
{
BaseForm.GlobalTheme = Enumerators.Theme.Light;
}
else if (themeSetting == "Dark")
{
BaseForm.GlobalTheme = Enumerators.Theme.Dark;
}
else
{
BaseForm.GlobalTheme = Enumerators.Theme.NotSet;
}
Application.Run(new Login());
}
}
}
tried doing it as MainForm.ApplyTheme, but that just returns to UserSettings nonetheless
Edit: adding snippets of MainForm:
namespace ME___Tooling_Designer_App.Forms;
public partial class MainForm : BaseForm
{
/// <summary>
/// Constructor
/// </summary>
public MainForm()
{
InitializeComponent();
ApplyTheme();
CreateDirectories();
CustomizeDesign();
InitializeDatFiles();
InitializeIniConfiguration();
ReadFont();
ReadComputer();
ReadSystem();
TestTrial();
DaysRemainColoring();
CompareComputerNameAndLicense();
lblUser.Text = Environment.UserName;
}
public override void ApplyThemeSpecific(ThemeSettings settings)
{
panelTopBar.BackColor = settings.PrimaryColor;
btnInfo.BackColor = settings.PrimaryColor;
btnMinimize.BackColor = settings.PrimaryColor;
btnExitTop.BackColor = settings.PrimaryColor;
panelCenter.BackColor = settings.SecondaryColor;
panelSideMenu.BackColor = settings.TertiaryColor;
panelSideMenuLogo.BackColor = settings.TertiaryColor;
btnMainMenu.BackColor = settings.TertiaryColor;
btnSettings.BackColor = settings.TertiaryColor;
btnSave.BackColor = settings.TertiaryColor;
btnLoad.BackColor = settings.TertiaryColor;
btnExit.BackColor = settings.TertiaryColor;
panelQuickView.BackColor = settings.QuaternaryColor;
panelMainMenu.BackColor = settings.QuinaryColor;
panelSettings.BackColor = settings.QuinaryColor;
btnNewProject.BackColor = settings.QuinaryColor;
btnExistingProject.BackColor = settings.QuinaryColor;
btnReadProject.BackColor = settings.QuinaryColor;
btnSearchProject.BackColor = settings.QuinaryColor;
btnUserSettings.BackColor = settings.QuinaryColor;
btnAppSettings.BackColor = settings.QuinaryColor;
}
The solution is to add a timer
Because your problem is to update all windows, you just need to add a timer control to each window.
Timer:
BaseForm:
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApp4 {
public partial class BaseForm : Form {
public BaseForm () {
}
private static Image baseImage=null;
public static Image BaseImage {
get {
return baseImage;
}
set {
baseImage = value;
}
}
}
}
SettingsForm:
using System;
namespace WindowsFormsApp4 {
public partial class SettingsForm : BaseForm {
public SettingsForm () {
InitializeComponent();
}
private void button1_Click (object sender, EventArgs e) {
BaseImage = Resource.tiger;
}
private void button2_Click (object sender, EventArgs e) {
BaseImage = Resource.windows;
}
private void timer1_Tick (object sender, EventArgs e) {
this.BackgroundImage = BaseImage;
}
}
}
Form1:
using System;
namespace WindowsFormsApp4 {
public partial class Form1 : BaseForm {
public Form1 () {
InitializeComponent();
}
private void button1_Click (object sender, EventArgs e) {
SettingsForm settingsForm=new SettingsForm();
settingsForm.ShowDialog();
}
private void timer1_Tick_1 (object sender, EventArgs e) {
this.BackgroundImage = BaseImage;
}
}
}
Resource.resx:
OutPut:
You can change it according to your needs.
If you have any questions, please comment below, and I will continue to follow up.
Try this code on all forms of your project on Activated and Load events.
Such as, MainForm:
private void MainForm_Activated(object sender, EventArgs e)
{
ApplyTheme();
}
Update: Try following line on BaseForm, if it works, add override on all forms and change the color values of all elements:
public virtual void ApplyThemeSpecific(ThemeSettings settings)
{
Background = settings.PrimaryColor; //for example
}
Update 2: Add a timer on all forms that checks theme change, and when theme changes, it changes the visual. Or you can make a event when theme changes.

Update UI from dynamic created class

I am dynamic creating several classes and labels. I want to update the label text from my class, but I don't have any idea how to implement it.
My class:
public partial class ScannerUtility : INotifyPropertyChanged
{
public System.Timers.Timer timerHeartBeat = new System.Timers.Timer();
public DateTime lastHeartBeat = new DateTime();
public string heartBeatMessage = string.Empty;
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public void EnableScannerUtility()
{
timerHeartBeat = new System.Timers.Timer();
timerHeartBeat.AutoReset = true;
timerHeartBeat.Interval = 5000;// 35000;
timerHeartBeat.Elapsed += TimerHeartBeat_Elapsed;
timerHeartBeat.Start();
}
private void TimerHeartBeat_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
TimeSpan timeSinceLastHeartbeat = DateTime.Now.ToUniversalTime() - lastHeartBeat;
if (timeSinceLastHeartbeat > TimeSpan.FromSeconds(30))
{
HeartBeatMessage = "No Answer from Scanner";
}
else
{
HeartBeatMessage = "Scanner OK";
}
}
public string HeartBeatMessage
{
get { return this.heartBeatMessage; }
set
{
if (value != this.heartBeatMessage)
{
this.heartBeatMessage = value;
NotifyPropertyChanged("heartBeatMessage");
}
}
}
}
And the loop where I created it from the main form:
private void CreateSckanners()
{
foreach (BarCodeNodes item in iBarcodeScanners)
{
ScannerUtility util = new ScannerUtility();
util.EnableScannerUtility();
Label lbl = new Label();
lbl.Text = item.IP.ToString();
lbl.Name = item.IP.ToString();
lbl.DataBindings.Add("Text", util, "HeartBeatMessage", false, DataSourceUpdateMode.OnPropertyChanged);
flowLayoutPanel1.Controls.Add(lbl);
flowLayoutPanel1.Update();
}
}
I want the Label to be updated when the timer is elapsed.
I'm affraid that you can not use DataBindigns in your situation. You have to stick whith the InvokeRequired style. Here, SO question about updating controls in another thread.
bokibeg is right. I put the code in case someone is interested.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += new EventHandler(Form1_Load);
}
void Form1_Load(object sender, EventArgs e)
{
ScannerUtility util = new ScannerUtility(SynchronizationContext.Current);
util.EnableScannerUtility();
util.HeartBeatMessage = "Waiting for scanner...";
this.SuspendLayout();
Label lbl = new Label();
lbl.Text = "Waiting for scanner...";
lbl.Name = "lblTimer";
lbl.Location = new System.Drawing.Point(15, 15);
lbl.AutoSize = true;
lbl.DataBindings.Add("Text", util, "HeartBeatMessage", false, DataSourceUpdateMode.OnPropertyChanged);
this.Controls.Add(lbl);
this.ResumeLayout(true);
}
}
public partial class ScannerUtility : INotifyPropertyChanged
{
private SynchronizationContext _uiThreadContext;
public System.Timers.Timer timerHeartBeat = new System.Timers.Timer();
public DateTime lastHeartBeat = new DateTime();
public string heartBeatMessage = string.Empty;
public event PropertyChangedEventHandler PropertyChanged;
public ScannerUtility(SynchronizationContext uiThreadContext)
{
_uiThreadContext = uiThreadContext;
}
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
_uiThreadContext.Post(onUIPropertyChanged, new PropertyChangedEventArgs(info));
}
;
}
private void onUIPropertyChanged(object state)
{
PropertyChanged(this, (PropertyChangedEventArgs)state);
}
public void EnableScannerUtility()
{
timerHeartBeat = new System.Timers.Timer();
timerHeartBeat.AutoReset = true;
timerHeartBeat.Interval = 5000;// 35000;
timerHeartBeat.Elapsed += TimerHeartBeat_Elapsed;
timerHeartBeat.Start();
}
private void TimerHeartBeat_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
TimeSpan timeSinceLastHeartbeat = DateTime.Now.ToUniversalTime() - lastHeartBeat;
if (timeSinceLastHeartbeat > TimeSpan.FromSeconds(30))
{
HeartBeatMessage = "No Answer from Scanner";
}
else
{
HeartBeatMessage = "Scanner OK";
}
}
public string HeartBeatMessage
{
get
{
return this.heartBeatMessage;
}
set
{
if (value != this.heartBeatMessage)
{
this.heartBeatMessage = value;
NotifyPropertyChanged("HeartBeatMessage");
}
}
}
}
}

Image will not update in code only custom control inheriting from button in WPF

I am currently trying to build a custom button control for a dice game I am writing in WPF. Everything is working correctly except that the image in the UI while it is running does not change when the the die value has changed. I can confirm through my debug sessions that the image source is changing as expected as well as all values are changing as expected but the image just doesn't seem to want to update. I've tried looking over many similar questions but none of the questions seem to apply to my particular situation it would seem. I am new to WPF and not quite sure what I am doing wrong here... my current code is as follows:
using BluffersDice.GameEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace BluffersDice.Interface.CustomControls
{
public class DieButton : Button
{
private Die _DieValue;
private readonly BitmapImage ONE_IMAGE = new BitmapImage(new Uri("/res/dice/1.png",UriKind.Relative));
private readonly BitmapImage TWO_IMAGE = new BitmapImage(new Uri("/res/dice/2.png", UriKind.Relative));
private readonly BitmapImage THREE_IMAGE = new BitmapImage(new Uri("/res/dice/3.png", UriKind.Relative));
private readonly BitmapImage FOUR_IMAGE = new BitmapImage(new Uri("/res/dice/4.png", UriKind.Relative));
private readonly BitmapImage FIVE_IMAGE = new BitmapImage(new Uri("/res/dice/5.png", UriKind.Relative));
private readonly BitmapImage SIX_IMAGE = new BitmapImage(new Uri("/res/dice/6.png", UriKind.Relative));
private const string HELD_LABEL_TEXT = "Held";
//private bool initcompleted = false;
private Label HoldLabel { get; set; }
public DieButton() : this(new Die())
{}
public DieButton(Die dieValue)
{
Background = Brushes.Transparent;
BorderBrush = new SolidColorBrush(Colors.Transparent);
BorderThickness = new Thickness(6);
HoldLabel = new Label() { MinHeight = 15 };
Click += This_OnClick;
DieValueChanged += DieValueChangedHandler;
dieValue.IsHeldChanged += DieValue_IsHeldChanged;
dieValue.DieValueChanged += DieValueChangedHandler;
_DieValue = dieValue;
Panel = new StackPanel()
{
Orientation = Orientation.Vertical,
Margin = new Thickness(8)
};
DieImage = new Image() { Source = GetDieImageSource() };
Panel.Children.Add(DieImage);
Panel.Children.Add(HoldLabel);
Content = Panel;
UpdateButtonContent();
//initcompleted = true;
}
private void This_OnClick(object sender, RoutedEventArgs e)
{
DieValue.ToggleHold();
}
public event EventHandler DieValueChanged;
public Die DieValue
{
get
{
return _DieValue;
}
set
{
_DieValue = value;
if (DieValueChanged != null)
{
DieValueChanged(this, new EventArgs());
}
}
}
private Image DieImage { get; set; }
private StackPanel Panel { get; set; }
private void DieValue_IsHeldChanged(object sender, EventArgs e)
{
var d = (Die)sender;
if (d.IsHeld)
{
BorderBrush = new SolidColorBrush(Colors.Yellow);
}
else
{
BorderBrush = new SolidColorBrush(Colors.Transparent);
}
HoldLabel.Content = DieValue.IsHeld ? HELD_LABEL_TEXT : string.Empty;
}
private void DieValueChangedHandler(object sender, EventArgs e)
{
DieImage.Source = GetDieImageSource();
UpdateButtonContent();
}
private ImageSource GetDieImageSource()
{
switch (DieValue.Value)
{
case 1:
return ONE_IMAGE;
case 2:
return TWO_IMAGE;
case 3:
return THREE_IMAGE;
case 4:
return FOUR_IMAGE;
case 5:
return FIVE_IMAGE;
case 6:
return SIX_IMAGE;
default:
return null;
}
}
private void UpdateButtonContent()
{
(Panel.Children[0] as Image).Source = GetDieImageSource();
}
}
}
Window Is being used on:
using BluffersDice.GameEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using BluffersDice.Interface.CustomControls;
namespace BluffersDice.Interface
{
/// <summary>
/// Interaction logic for UserTurn.xaml
/// </summary>
public partial class PlayerTurn : Window
{
public Turn TurnState { get; set; }
private Roll CurrentRoll { get; set; }
public PlayerTurn()
{
CurrentRoll = new Roll();
InitializeComponent();
btn_Die1 = new DieButton(CurrentRoll.Dice[0]);
btn_Die2 = new DieButton(CurrentRoll.Dice[1]);
btn_Die3 = new DieButton(CurrentRoll.Dice[2]);
btn_Die4 = new DieButton(CurrentRoll.Dice[3]);
btn_Die5 = new DieButton(CurrentRoll.Dice[4]);
GameState.Caller.StartNewTurn();
TurnState = GameState.Caller.StartNewTurn();
lbl_PlayerTitle.Text = string.Format(lbl_PlayerTitle.Text, GameState.Caller.Id);
}
private void btn_DieValuechanged(object sender, EventArgs ea)
{
var d = (Die)sender;
MessageBox.Show(String.Format("Die Button {0} Value Changed To {1}", d.Id, d.Value));
}
private void DieValueChanged(object sender, EventArgs e)
{
var d = (Die)sender;
//MessageBox.Show(String.Format("Die {0} Value Changed To {1}", d.Id, d.Value));
}
private void RollDice_btnClick(object sender, RoutedEventArgs e)
{
CurrentRoll.RollDice();
}
}
}
Each time you want to change your image try doing the below
= new BitmapImage(new Uri(...
I have read around that usually works or you can follow the solution discussed here
http://social.msdn.microsoft.com/Forums/en/wpf/thread/976e8d89-aafd-4708-9e4f-87655a5da558

Loading animation in new window when WPF datagrid is loading

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 = "";
}
}
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
}

.NET Propertygrid refresh trouble

Property grid do not show new value of selected object.
For example:
o.val = "1";
pg.SelectedObject = o;
o.val = "2";
pg.Refresh();
The property in property grid is still "1";
It is changing only if you click on this property.
Or like that:
o.val = "1";
pg.SelectedObject = o;
o.val = "2";
pg.SelectedObject = o;
but in this case focus will be changed to PropertyGrid.
As I told you in my comment, your code is not enough to understand your issue. Presented like this it should work. Here is mine that works well:
public class Target
{
private int _myInt = 1;
public int MyInt { set; get; }
public static Target target = new Target();
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Button button = new Button()
{
Text = "Click me",
Dock = DockStyle.Bottom
};
Form form = new Form
{
Controls = {
new PropertyGrid {
SelectedObject = Target.target,
Dock = DockStyle.Fill,
},
button
}
};
button.Click += new EventHandler(button_Click);
Application.Run(form);
}
static void button_Click(object sender, EventArgs e)
{
Target.target.MyInt = 2;
Form form = Form.ActiveForm;
(form.Controls[0] as PropertyGrid).Refresh();
}
}
The call to Refresh() actually rebuilds the grid. Remove it and you will see the change only when you click the property.
Cause you just not gave some code, here is a working example.
Just put a Button and a PropertyGrid onto a form.
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace WindowsFormsApplication
{
public partial class FormMain : Form
{
Random rand;
MyObject obj;
public FormMain()
{
InitializeComponent();
rand = new Random();
obj = new MyObject();
propertyGrid1.SelectedObject = obj;
}
private void button1_Click(object sender, EventArgs e)
{
obj.MyValue = rand.Next();
obj.IsEnabled = !obj.IsEnabled;
obj.MyText = DateTime.Now.ToString();
propertyGrid1.Refresh();
}
}
public class MyObject : INotifyPropertyChanged
{
private int _MyValue;
public int MyValue
{
get
{
return _MyValue;
}
set
{
_MyValue = value;
NotifyPropertyChanged("MyValue");
}
}
private string _MyText;
public string MyText
{
get
{
return _MyText;
}
set
{
_MyText = value;
NotifyPropertyChanged("MyText");
}
}
private bool _IsEnabled;
public bool IsEnabled
{
get
{
return _IsEnabled;
}
set
{
_IsEnabled = value;
NotifyPropertyChanged("IsEnabled");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
}

Categories

Resources