A UWP UserControl with 2 buttons
public sealed partial class SaveChangesUserControl : UserControl
{
public bool CanGo { get; set; }
public SaveChangesUserControl()
{
InitializeComponent();
}
private void Leave(object sender, EventArgs e)
{
CanGo = true;
}
private void Stay(object sender, EventArgs e)
{
CanGo = false;
}
}
SaveChangesUserControl will be in a xaml page. I can bind the visibility to a property in the xaml page. Leave and Stay are event handlers for buttons in SaveChangesUserControl. How do I capture CanGo as the return value of SaveChangesUserControl?
Something like bool canGo = SaveChangesUserControl would be nice.
Like a ContentDialog, but not a ContentDialog
You could use AutoResetEvent class to do a thread synchronization. When signaled, reset automatically after releasing a single waiting thread.
Please check the following code:
SaveChangesUserControl.xaml.cs
private static AutoResetEvent Locker = new AutoResetEvent(false);
public async Task<bool> ShowAsync()
{
Visibility = Visibility.Visible;
await Task.Run(() => {
Locker.WaitOne(); //Wait a singal
});
return CanGo;
}
private void Leave(object sender, RoutedEventArgs e)
{
Visibility = Visibility.Collapsed;
CanGo = true;
Locker.Set(); //Release a singal
}
private void Stay(object sender, RoutedEventArgs e)
{
Visibility = Visibility.Collapsed;
CanGo = false;
Locker.Set(); //Release a singal
}
MainPage.xaml.cs
private async void Button_Click(object sender, RoutedEventArgs e)
{
var t = await myUserControl.ShowAsync(); //Call the method, you could get a return value after you click on user control
}
Related
I want to know the the task status runnning in A button event from the other button click.
Like this.
private void button1_Click(object sender, EventArgs e)
{
Task.Run(()=>{
//The method to take long time
//For example
Thread.Sleep(5000)
;});
}
private coid button2_Click(object sender, EventArgs e)
{
//until 5000ms
//the method to know the above task status (Runnning....)
//after 5000ms
//the method to know the above task status (Conpleted....)
}
It's not entirely clear what you're trying to achieve, but if you want to check the status of the task, you can get its reference when calling Task.Run()
private Task _task;
private void button1_Click(object sender, EventArgs e)
{
_task = Task.Run(() => Thread.Sleep(5000));
}
private void button2_Click(object sender, EventArgs e)
{
if (_task?.Status == TaskStatus.RanToCompletion)
//do something
}
The answer is as vague as the question, so if you could give me a bit more details, I could come up with a better more tailored answer.
Again, it's very unclear what you're looking for here...but this is an expanded version of Faylit's example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Task T = null;
private void Form1_Load(object sender, EventArgs e)
{
updateStatus();
}
private async void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
await (T = Task.Run(() =>
{
updateStatus();
System.Threading.Thread.Sleep(5000);
}));
button1.Enabled = true;
updateStatus();
}
private void button2_Click(object sender, EventArgs e)
{
updateStatus();
}
private void updateStatus()
{
if (label1.InvokeRequired)
{
label1.Invoke((MethodInvoker)delegate
{
updateStatus();
});
}
else
{
if (T == null)
{
label1.Text = "Task not started.";
}
else if (!T.IsCompleted)
{
label1.Text = "Task running...";
}
else
{
label1.Text = "Task completed.";
}
}
}
}
It might give you some more ideas.
This question already has answers here:
Change a textbox's text value on a UserControl from a Window in WPF
(2 answers)
Closed 3 years ago.
Ok, I have two windows in my WPF app. I want to change the text of a textbox, from a second window. This should also happen parallel.
I know, this is about multithreadin, but I know very little about it.
This is what my current code looks like, but this is for copying textbox text.
private void copyButton_Click(object sender, RoutedEventArgs e)
{
secondWindow = new SecondWindow();
secondWindow.textBoxS.Text = textBox.Text;
secondWindow.Show();
}
But, I want to change textbox texts dynamically between the MainWindow and the Second window.
So I tried something like this:
private void textBox_TextChanged(object sender, TextChangedEventArgs e)
{
Task t = Task.Run(() =>
{
secondWindow = new SecondWindow();
secondWindow.textBoxS.Text = textBox.Text;
secondWindow.Show();
});
t.Start();
}
There are several ways to do this. I put two way in below:
Method 1
You can create a public method (e.g. SetTextBoxValue) and
pass the window that contains the TextBox to other window. Then change the TextBox value using that method. like this:
MainWindow
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
public void SetTextBoxValue(string value)
{
SampleTextBox.Text = value;
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
var otherWindow = new AnotherWindow(this);
otherWindow.Show();
}
}
Other Window
public partial class AnotherWindow
{
private readonly MainWindow _mainWindow;
public AnotherWindow(MainWindow mainWindow)
{
_mainWindow = mainWindow;
InitializeComponent();
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
_mainWindow.SetTextBoxValue("New value from other window");
}
}
Method 2
You can create a event for other window and subscribe to it in main window. like this:
MainWindow
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
var otherWindow = new AnotherWindow();
otherWindow.TextBoxValueChanged += OtherWindowOnTextBoxValueChanged;
otherWindow.Show();
}
private void OtherWindowOnTextBoxValueChanged(object sender, TextBoxValueEventArgs e)
{
SampleTextBox.Text = e.NewValue;
}
}
Other Window
public partial class AnotherWindow
{
public event EventHandler<TextBoxValueEventArgs> TextBoxValueChanged;
public AnotherWindow()
{
InitializeComponent();
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
var newValue = "New value from other window";
OnTextBoxValueChanged(new TextBoxValueEventArgs(newValue));
}
protected virtual void OnTextBoxValueChanged(TextBoxValueEventArgs e)
{
TextBoxValueChanged?.Invoke(this, e);
}
}
public class TextBoxValueEventArgs : EventArgs
{
public string NewValue { get; set; }
public TextBoxValueEventArgs(string newValue)
{
NewValue = newValue;
}
}
OUTPUT
try this, initialize the second window in first window constructor
private SecondWindow _secondWindow;
public FirstWindow()
{
_secondWindow = new SecondWindow();
}
and your second form before constructor
private string text;
public string Text
{
get
{
return text;
}
set
{
textBoxOfSecondWindow.Text = value;
text = value;
}
}
then in the copybutton function
private void copyButton_Click(object sender, RoutedEventArgs e)
{
_secondWindow.Text= textBox.Text;
_secondWindow.Show();
}
in the textchange of the first window
private void textBox_TextChanged(object sender, TextChangedEventArgs e)
{
_secondwindow.Text = textBox.Text;
}
in your second window, place this code in the textBox_TextChanged method.
((MainWindow)Application.Current.MainWindow).txtFirstWindow.Text = txtSecondWindow.Text;
I'm pretty new to C# and WPF, so please forgive me if my question maybe stupid. I come from the C++ world
I have an application that has a button, as long as I press the button I want to record a sounde from the microphone and when I release the button then the recording should stop. Just like the voice message in WhatsApps. I added the events PreviewMouseDown="ButtonLiveDown" and PreviewMouseUp="ButtonLiveUp" to my button and I can see that they are fired:
My main class:
m_MyLive = new AudioLive();
m_MyLive.Init(this);
private void ButtonLiveDown(object sender, MouseButtonEventArgs e)
{
m_MyLive.StartLive();
}
private void ButtonLiveUp(object sender, MouseButtonEventArgs e)
{
m_MyLive.EndLive();
}
and my Live Class:
class AudioLive
{
private MainWindow m_mainWindow;
private WaveIn m_Recorder;
private BufferedWaveProvider m_BufferedWaveProvider;
private SavingWaveProvider m_SavingWaveProvider;
private WaveOut m_Player;
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (m_Recorder != null)
{
m_Recorder.Dispose();
}
m_Recorder = null;
if (m_SavingWaveProvider != null)
{
m_SavingWaveProvider.Dispose();
}
m_SavingWaveProvider = null;
}
private void RecorderOnDataAvailable(object sender, WaveInEventArgs waveInEventArgs)
{
m_BufferedWaveProvider.AddSamples(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
}
public bool Init(MainWindow mainWindow)
{
m_mainWindow = mainWindow;
m_Recorder = new WaveIn();
m_Recorder.DataAvailable += RecorderOnDataAvailable;
// set up our signal chain
m_BufferedWaveProvider = new BufferedWaveProvider(m_Recorder.WaveFormat);
m_SavingWaveProvider = new SavingWaveProvider(m_BufferedWaveProvider, "live.wav");
// set up playback
m_Player = new WaveOut();
m_Player.Init(m_SavingWaveProvider);
return true;
}
public void SetMicVolume(int nVol)
{
....
}
public void StartLive()
{
SetMicVolume(100);
// begin playback & record
m_Player.Play();
m_Recorder.StartRecording();
}
public void EndLive()
{
// stop recording
m_Recorder.StopRecording();
// stop playback
m_Player.Stop();
}
}
But this doesn't work, as long as I press the button down it seems that it stops working till I release the button. From C++ I know this, as long as I press the button the system is busy with the pressed Event and can't continue to work. Is it the same with C# & WPF? If yes, is there any other way to handle my feature wish?
If I understand your question, then yes, you will have to deal with UI blocking in this case. Use a background worker to kick the event on mouse down and background worker cancellation on mouse up. Example below shows with mouseup and mouse down event handelers as oppossed to the previewmouse up and down
Updated Example to help with understanding
XAML BUTTON:
<Button x:Name="RecordBtn" Content="Button" HorizontalAlignment="Left" Margin="363,199,0,0" VerticalAlignment="Top" Width="75" MouseDown="Button_MouseDown" MouseUp="Button_MouseUp"/>
xaml code behind showing background worker kicking and holding the process:
public partial class MainWindow : Window
{
private readonly BackgroundWorker worker = new BackgroundWorker();
AudioLive m_MyLive = new AudioLive();
Stopwatch stopWatch = new Stopwatch();
public MainWindow()
{
InitializeComponent();
AddHandler(FrameworkElement.MouseDownEvent, new MouseButtonEventHandler(Button_MouseDown), true);
AddHandler(FrameworkElement.MouseUpEvent, new MouseButtonEventHandler(Button_MouseUp), true);
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.WorkerSupportsCancellation = true;
m_MyLive.Init(this);
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
if (!m_MyLive.IsRecordinginProgress() && !worker.CancellationPending)
{
m_MyLive.StartLive();
stopWatch.Reset();
stopWatch.Start();
}
while (m_MyLive.IsRecordinginProgress() && !worker.CancellationPending)
{
this.Dispatcher.Invoke(() =>
{
updateLabel(String.Format("{0:0.#}", TimeSpan.FromMilliseconds(stopWatch.ElapsedMilliseconds).TotalSeconds) + " seconds");
});
}
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
m_MyLive.EndLive();
stopWatch.Stop();
updateLabel(String.Format("{0:0.#}", TimeSpan.FromMilliseconds(stopWatch.ElapsedMilliseconds).TotalSeconds) + " seconds");
}
private void updateLabel(string text)
{
RecordBtn.Content = text;
}
private void Button_MouseDown(object sender, MouseButtonEventArgs e)
{
worker.RunWorkerAsync();
}
private void Button_MouseUp(object sender, MouseButtonEventArgs e)
{
worker.CancelAsync();
}
}
Updated AudioLive to add property isRecording to use in our background worker:
public class AudioLive
{
private MainWindow m_mainWindow;
private WaveIn m_Recorder;
private BufferedWaveProvider m_BufferedWaveProvider;
private SavingWaveProvider m_SavingWaveProvider;
private WaveOut m_Player;
private bool isRecording { get; set; }
public bool IsRecordinginProgress()
{
return isRecording;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (m_Recorder != null)
{
m_Recorder.Dispose();
}
m_Recorder = null;
if (m_SavingWaveProvider != null)
{
m_SavingWaveProvider.Dispose();
}
m_SavingWaveProvider = null;
}
private void RecorderOnDataAvailable(object sender, WaveInEventArgs waveInEventArgs)
{
m_BufferedWaveProvider.AddSamples(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
}
public bool Init(MainWindow mainWindow)
{
m_mainWindow = mainWindow;
m_Recorder = new WaveIn();
m_Recorder.DataAvailable += RecorderOnDataAvailable;
// set up our signal chain
m_BufferedWaveProvider = new BufferedWaveProvider(m_Recorder.WaveFormat);
m_SavingWaveProvider = new SavingWaveProvider(m_BufferedWaveProvider, "live.wav");
// set up playback
m_Player = new WaveOut();
m_Player.Init(m_SavingWaveProvider);
return true;
}
public void SetMicVolume(int nVol)
{
}
public void StartLive()
{
SetMicVolume(100);
// begin playback & record
m_Player.Play();
m_Recorder.StartRecording();
isRecording = true;
}
public void EndLive()
{
// stop recording
m_Recorder.StopRecording();
// stop playback
m_Player.Stop();
isRecording = false;
}
}
I'm trying to implement a customized exit prompt in my WinForms. (I should not be using DialogBox)
I have a User Control Object placed in my main form that is invisible and disabled by default. Clicking in a certain button I have placed on the form shows and enables the object, disabling everything in my form except the User Control.
private void btn_close_Click(object sender, EventArgs e) {
prompt1.Visible = true;
prompt1.Enabled = true;
disableControls();
//Wait for a button to be pressed in prompt1
//Make an action based on a button pressed.
//closeApp returns a boolean
if (!prompt1.closeApp)
{
prompt1.Visible = false;
prompt1.Enabled = false;
enableControls();
}
else
{
Application.Exit();
}
}
Here's my code at the prompt object:
public partial class Prompt : UserControl
{
bool exit;
public bool closeApp
{
get{return exit;}
}
public Prompt()
{
InitializeComponent();
}
private void btn_yes_Click(object sender, EventArgs e)
{
exit = true;
}
private void btn_no_Click(object sender, EventArgs e)
{
exit = false;
this.Hide();
}
}
What I want to do is wait for a button to be pressed in my prompt object before proceeding to the next line in the btn_close_Click().
What should I do? Is there a better way to implement this?
Add events to your usercontrol then handle those events on your main form.
In your usercontrol:
public event EventHandler<EventArgs> ExitCancelled;
public event EventHandler<EventArgs> ExitApplication;
private void btn_yes_Click(object sender, EventArgs e)
{
ExitApplication?.Invoke(this, EventArgs.Empty);
}
private void btn_no_Click(object sender, EventArgs e)
{
ExitCancelled?.Invoke(this, EventArgs.Empty);
}
Handle the events on your form:
public void prompt1_ExitApplication(object sender, EventArgs e)
{
Application.Exit();
}
public void prompt1_ExitCancelled(object sender, EventArgs e)
{
prompt1.Hide();
enablecontrols();
}
I have a button that on click event goes and get data from server and displays that on a grid.
The code is like below:
private void btnSearch_Click(object sender, EventArgs e)
{
// Here I should do something in order to know if the async ProcessSearch method is busy..
// if not busy then I will execute it if not then I will return.
// shows loading animation
ShowPleaseWait(Translate("Searching data. Please wait..."));
ProcessSearch();
}
private async void ProcessSearch()
{
Data.SeekWCF seekWcf = new Data.SeekWCF();
_ds = await seekWcf.SearchInvoiceAdminAsync(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value));
seekWcf.Dispose();
if (_ds != null)
{
SetupInvoiceGrid();
}
// hides the loading animation
HidePleaseWait();
}
How can I know if the async method ProcessSearch is busy or running so I can prevent the user to execute the method again when clicking the button again.
You could just set a boolean:
private bool isSearching = false;
private void btnSearch_Click(object sender, EventArgs e)
{
if (isSearching)
return;
// shows loading animation
ShowPleaseWait(Translate("Searching data. Please wait..."));
ProcessSearch();
}
private async void ProcessSearch()
{
isSearching = true;
// do other stuff
isSearching = false;
}
If you're concerned about concurrency, you could add a lock:
private bool isSearching = false;
private object lockObj = new object();
private void btnSearch_Click(object sender, EventArgs e)
{
lock (lockObj)
{
if (isSearching)
return;
else
isSearching = true;
}
// shows loading animation
ShowPleaseWait(Translate("Searching data. Please wait..."));
ProcessSearch();
}
private async void ProcessSearch()
{
// do other stuff
isSearching = false;
}