Telegram InlineButton Callbackdata Problem - c#

I want when a user clicks an inline button, a message sent to another user!
Here is my code:
//creating inline keyboard
InlineKeyboardButton accept= new InlineKeyboardButton();
InlineKeyboardButton reject = new InlineKeyboardButton();
InlineKeyboardButton[] buttons = new InlineKeyboardButton[]
{
accept, reject
};
InlineKeyboardMarkup inline = new InlineKeyboardMarkup(buttons);
//giving inline buttons text and callback data
accpet.Text = "accept";
reject.Text = "reject";
accept.CallbackData = "accept";
reject.CallbackData = "reject";
//instantiation "CallbackQuery" class
CallbackQuery callbackQuery = new CallbackQuery();
//send a text message to someone else if "callbackQuery.Data" was same a "accept" button callback data.
//This Part Doesn't Works. When I click accept button it does nothing!
if (callbackQuery.Data == "accept")
{
await botClient.SendTextMessageAsync(
chatid,
"Hello World."
);
}
Thanks A lot For Your Helps :)

You're doing wrong, You should wait until receiving CallbackQuery update, Not creating new CallbackQuery(); And then try processing.
Telegram has something called Updates, Which means events when new message sent Or edited, Button pressed, User joined, etc.
So, You should create a OnCallbackQuery event, To handle any callback button pressed like this:
First, Creating the handler method:
botClient.OnCallbackQuery += botClient_OnCallbackQuery;
private void botClient_OnCallbackQuery(object sender, CallbackQueryEventArgs e)
{
// Send the message to any one you want
ChatId chatId = /*Put any chat ID you want*/;
await botClient.SendTextMessageAsync(chatId, "Hello World.");
}
Second, You should handle any message via OnMessage event like this:
botClient.OnMessage += botClient_OnMessage;
private async void botClient_OnMessage(object sender, MessageEventArgs e)
{
var message = e.Message;
if (message.text == '/start')
{
var accept = InlineKeyboardButton.WithCallbackData("Accept", "accept");
var reject = InlineKeyboardButton.WithCallbackData("Reject", "reject");
await botClient.SendTextMessageAsync(message.Chat.Id, "Accept Or Reject..", replyMarkup: new InlineKeyboardMarkup([accept, reject]));
}
}

Related

Chatbox not working c#,Visual Studio ,Winforms,Bunifu UI

I have a problem that i dont understand at all , i need your help...
I am working in a chat , i will do it with sockets , but the problem isnot this ,
I created a control user to my chat box... and another to my bubbles i am trying to use this control users from my main form
private void button1_Click_1(object sender, EventArgs e)
{
chatbox a = new bunifchat.chatbox();
a.send2message("ABC");
}
chatbox is the name of my controlUser and i am trying to use his method send2message, i know that it works but not correctly.
public void send2message(String message)
{
bubble bbl = new bunifchat.bubble(message);
bbl.Location = bubble1.Location; bbl.Left += 100; //add intent
bbl.Size = bubble1.Size;
bbl.Anchor = bubble1.Anchor;
bbl.Top = bbl_old.Bottom + 20;
panel2.Controls.Add(bbl);
//bottom.Top = bbl.Bottom + 50;
bbl_old = bbl; //safe the last added object
}
this method receive the string and create the bubble entering to other controlUser, it works when i run it from the ControlUser Chatbox with the next code:
private void buttonx_Click(object sender, EventArgs e)
{
//panel1.VerticalScroll.Value = panel1.VerticalScroll.Maximum;
String respuesta = txtbox.Text;
sendmessage("hola mundo");
send2message(respuesta);
panel2.VerticalScroll.Value = panel2.VerticalScroll.Maximum;
}
but if i run it from my main form , nothing happens,the code of my bubble is this:
public bubble(String message)
{
InitializeComponent();
label1.Text = message;
Setheight();
}
if i am not explicit, please ask , i need help
enter image description here
when i press the button green , it create more bubbles(blue rectangules) , but i want to send the content from my main form and not from my chat box.
i will do it with sockets
Does that mean you use a socket to receive data on a different thread than the UI-thread?
If so, you need to check, if oyu need to invoke before accessing / creating a new object.
private bool AddMessage(string msg)
{
if (this.InvokeRequired)
return (bool)this.Invoke((Func<string,bool>)AddMessage, msg);
//DO stuff here
send2message(msg);
return false;
}

Wait for button click while reading or during a loop

I am creating a time clock program. Our office staff would like to be able to send messages to specific employees when they clock in. The issue I have is if there are multiple messages to display, it loops through to the last one.
while(reader.Read()
{
richtextbox.Text = reader["Message"].ToString();
//need to pause here and wait for them to press the acknowledge button
{
Is there a way to wait or pause until the press the acknowledge button.
Any help is appreciated.
ps. I have tried using
public static class Utils
{
public static Task WhenClicked(this Control target)
{
var tcs = new TaskCompletionSource<object>();
EventHandler onClick = null;
onClick = (sender, e) =>
{
target.Click -= onClick;
tcs.TrySetResult(null);
};
target.Click += onClick;
return tcs.Task;
}
}
from this thread Wait until a click event has been fired C# but It did the same thing and blew past the button and showed the last message again.
I would approach the problem like this. Make your reader load all of the messages into a collection like a Queue (which is a first-in-first-out collection, ideal for what you are trying to do.) After the loop, if there are any messages, display the first one. Wire up the click event to a similar block of code that will display the next message (if any more exist) each time the button is clicked. The code would look like this:
Queue<string> EmployeeMessages = new Queue<string>();
private void OnLogin()
{
var reader = GetReader();
while (reader.Read())
{
EmployeeMessages.Enqueue(reader["Message"].ToString());
}
if (EmployeeMessages.Count > 0)
{
label1.Text = EmployeeMessages.Dequeue();
}
}
private void button1_Click(object sender, EventArgs e)
{
if (EmployeeMessages.Count > 0)
{
label1.Text = EmployeeMessages.Dequeue();
}
}

How to put a cancel button when connecting

I make a connection in C# with a login and a password and I would like
put a button to cancel the connection to the database if it gets too much
long.
I would like to know how to do it and put it in a thread if possible.
Here is the code:
private void btncon_Click(object sender, EventArgs e)
{
string strLogin = tblogin.Text.Trim();
string pass = tbpwd.Text;
bool success = false;
if (String.IsNullOrWhiteSpace(strLogin) || String.IsNullOrWhiteSpace(pass))
{
MessageBox.Show("Veuillez remplir tous les champs SVP ");
}
else if(String.IsNullOrEmpty(strLogin) || String.IsNullOrEmpty(pass)){
MessageBox.Show("Veuillez remplir tous les champs SVP ");
}
else
{
model.Connexion cm = new model.Connexion();
pass = Snippets.SHA1Util.SHA1HashStringForUTF8String(pass).ToString();
string[] user = cm.login(strLogin, pass);
if(user[0] != null)
{
Int32.TryParse(user[0], out iduser);
Int32.TryParse(user[1], out idGrp);
Int32.TryParse(user[2], out idbtq);
nom = user[3];
if (idGrp != 3)
success = true;
else
{
MessageBox.Show("Accès Non autorisé , Veuillez contacter l'administrateur");
success = false;
}
}
else
{
MessageBox.Show("Email ou mot de passe incorrect.");
success = false;
}
}
if (success)
{
main Principale = new main();
Principale.Show();
Hide();`
}
}
Problem is that when user clicks the Cancel button, there is no way to cancel the cm.login() method gracefully while it's executing. You could use Thread.Abort() to terminate login forcefully, but it's unsafe and strongly discouraged, because making it right would require execute code in another AppDomain and would make the code very complicated.
Fortunatelly, you can still implement Cancel button, if the following conditions are true:
It is safe to call cm.login() on another thread
Letting cm.login() finish in the background (on another thread) after user clicks on the Cancel button does not have undesired effects.
This code also assumes that it is an Winform app (but solution for WPF app would be very similar). It also assumes that main form has a button btnCancel that is hidden (Visible=false) and it's Click event handler is set to btnCancel_Click method.
TaskCompletionSource<Object> CancelLoginTcs = new TaskCompletionSource<Object>();
// Make button click handler method async
private async void btncon_Click(object sender, EventArgs e)
{
try
{
// Make Cancel button visible, so that user can click on it
btnCancel.Visible = true;
// Prepare everything needed to start login
//var strLogin = ...;
//var pass = ...;
//model.Connexion cm = new model.Connexion();
// ...
// Start login on another thread
var loginTask = Task<string[]>.Run(() => cm.login(strLogin, pass));
// Create task that is used to wake-up main thread, when user clicks
// on the Cancel button before login finishes.
CancelLoginTcs = new TaskCompletionSource<Object>();
// Wait for login task or cancel task to complete, whichever finishes first
await Task.WhenAny(loginTask, CancelLoginTcs.Task);
if (CancelLoginTcs.Task.IsCanceled)
{
// User clicked on the Cancel button.
// Login method will be running in the background, until it
// finishes. This assumes that it is safe to do so.
// Here you should do neccessary clean-up, inform user, etc.
// ...
}
else
{
// Login finished and user did NOT click on the Cancel button.
try
{
// Simply read result of login. If an Exception occured during login,
// it will be rethrow now, so you should handle it appropriatelly
var user = loginTask.Result;
// Here program continues in a usual way
// ...
}
catch(Exception E)
{
// Handle login exception
// ...
}
}
}
finally
{
// Hide Cancel button again
btnCancel.Visible = false;
CancelLoginTcs = null;
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
// Set cancel task to cancelled state.
// This will wake-up main thread and let it continue
CancelLoginTcs.SetCanceled();
}

In UWP how to display a messagebox from a synchronous function (ie. not async)

Is there a way to wrap the UWP async function for creating dialog boxes in such a way that they can be called from a normal method without the async keyword? Example:
var msgbox = new ContentDialog
{
Title = "Error",
Content = "Already at the top of the stack",
CloseButtonText = "OK"
};
await msgbox.ShowAsync();
No, there is no way to do this at the moment. If you try to block waiting for the dialog to close, your app will deadlock.
Here is how I do it (I saw this in some live demo back when UWP was just introduced):
var msgbox = new ContentDialog
{
Title = "Error",
Content = "Already at the top of the stack",
CloseButtonText = "OK"
};
var ignored = msgbox.ShowAsync();
This works as expected in a non-async void method.
public Task<ContentDialogResult> MsgBox(string title, string content)
{
Task<ContentDialogResult> X = null;
var msgbox = new ContentDialog
{
Title = title,
Content = content,
CloseButtonText = "OK"
};
try
{
X = msgbox.ShowAsync().AsTask<ContentDialogResult>();
return X;
}
catch {
return null;
}
}
private void B1BtnBack_Click(object sender, RoutedEventArgs e)
{
MsgBox("Beep", "Already at the top of stack");
return;
// ^^^ Careful here. MsgBox returns with an active task
// running to display dialog box. This works because
// the next statement is a return that directly
// returns to the UI message loop. And the
// ContentDialog is modal meaning it disables
// the page until ok is clicked in the dialog box.
}

Using FileSavePicker with MessageDialog's IUICommand event

Individually, all code works perfectly. The snippet for saving the file, the snippet for picking a directory to save it to and also the message dialog works great.
But when I tie it all together, I get an access denied. I am not using the DocumentsLibrary capability since it is not required of me to do so in this case, however, enabling this capability after running into issues confirmed that it is not the issue.
Scenario:
User wants to create a new document after entering text in the text box. A MessageDialog appears, asking them if they want to save changes to the existing file first - the user clicks Yes (save file).
Now, here is where you handle the event that was raised by the MessageDialog.
Inside the IUICommand command event handler, you test for which button was clicked, and act accordingly.
I did this with a switch statement:
switch(command.Label) {
case "Yes":
SaveFile(); // extension method containing save file code that works on its own
break;
case "No":
ClearDocument();
break;
default:
break;
}
Now, each case works great except for the Yes button. When you click yes, an e tension method is called which has code that saves to a file
It is when you click yes button that you get the ACCESS DENIED exception. Details of the exception didn't reveal anything.
I think that it has something to do with how I am using the MesaageDialog. But after searching for hours I have yet to find a sample on how to save a file with the FileSavePicker when a MesaageDialog button is pressed.
Any ideas in how this should be done?
Update w/ Code
When the user clicks the New document button on the AppBar, this method fires:
async private void New_Click(object sender, RoutedEventArgs e)
{
if (NoteHasChanged)
{
// Prompt to save changed before closing the file and creating a new one.
if (!HasEverBeenSaved)
{
MessageDialog dialog = new MessageDialog("Do you want to save this file before creating a new one?",
"Confirmation");
dialog.Commands.Add(new UICommand("Yes", new UICommandInvokedHandler(this.CommandInvokedHandler)));
dialog.Commands.Add(new UICommand("No", new UICommandInvokedHandler(this.CommandInvokedHandler)));
dialog.Commands.Add(new UICommand("Cancel", new UICommandInvokedHandler(this.CommandInvokedHandler)));
dialog.DefaultCommandIndex = 0;
dialog.CancelCommandIndex = 2;
// Show it.
await dialog.ShowAsync();
}
else { }
}
else
{
// Discard changes and create a new file.
RESET();
}
}
And the FileSavePicker stuff:
private void CommandInvokedHandler(IUICommand command)
{
// Display message showing the label of the command that was invoked
switch (command.Label)
{
case "Yes":
MainPage rootPage = this;
if (rootPage.EnsureUnsnapped())
{
// Yes was chosen. Save the file.
SaveNewFileAs();
}
break;
case "No":
RESET(); // Done.
break;
default:
// Not sure what to do, here.
break;
}
}
async public void SaveNewFileAs()
{
try
{
FileSavePicker saver = new FileSavePicker();
saver.SuggestedStartLocation = PickerLocationId.Desktop;
saver.CommitButtonText = "Save";
saver.DefaultFileExtension = ".txt";
saver.FileTypeChoices.Add("Plain Text", new List<String>() { ".txt" });
saver.SuggestedFileName = noteTitle.Text;
StorageFile file = await saver.PickSaveFileAsync();
thisFile = file;
if (file != null)
{
CachedFileManager.DeferUpdates(thisFile);
await FileIO.WriteTextAsync(thisFile, theNote.Text);
FileUpdateStatus fus = await CachedFileManager.CompleteUpdatesAsync(thisFile);
//if (fus == FileUpdateStatus.Complete)
// value = true;
//else
// value = false;
}
else
{
// Operation cancelled.
}
}
catch (Exception exception)
{
Debug.WriteLine(exception.InnerException);
}
}
Any progress on this issue? I currently have the same problem. I have also found that the same problem occurs if a second MessageDialog is shown in the IUICommand event.
My solution is to cancel the first operation (that shows the first message dialog). Here some code I’m using (it’s accessible in a global object):
private IAsyncInfo mActiveDialogOperation = null;
private object mOperationMutex = new object();
private void ClearActiveOperation(IAsyncInfo operation)
{
lock (mOperationMutex)
{
if (mActiveDialogOperation == operation)
mActiveDialogOperation = null;
}
}
private void SetActiveOperation(IAsyncInfo operation)
{
lock (mOperationMutex)
{
if (mActiveDialogOperation != null)
{
mActiveDialogOperation.Cancel();
}
mActiveDialogOperation = operation;
}
}
public void StopActiveOperations()
{
SetActiveOperation(null);
}
public async void ShowDialog(MessageDialog dialog)
{
StopActiveOperations();
try
{
IAsyncOperation<IUICommand> newOperation = dialog.ShowAsync();
SetActiveOperation(newOperation);
await newOperation;
ClearActiveOperation(newOperation);
}
catch (System.Threading.Tasks.TaskCanceledException e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
}
}
So every time I want to show a MessageDialog I call ShowDialog. This will cancel the current dialog if any (then a TaskCanceledException occurs).
In the case when I will use a FileSavePicker, I call StopActiveOperations before PickSaveFileAsync is called.
This works but I can’t say I like it. It feels like I’m doing something wrong.
OK, now I have figured it out :-). The documentation says explicit that you shouldn’t show new popups/file pickers in the UICommand:
http://msdn.microsoft.com/en-US/library/windows/apps/windows.ui.popups.messagedialog.showasync
This is an example of a bad way to do it:
private async void Button_Click(object sender, RoutedEventArgs e)
{
MessageDialog dialog = new MessageDialog("Press ok to show new dialog (the application will crash).");
dialog.Commands.Add(new UICommand("OK", new UICommandInvokedHandler(OnDialogOkTest1)));
dialog.Commands.Add(new UICommand("Cancel"));
await dialog.ShowAsync();
}
private async void OnDialogOkTest1(IUICommand command)
{
MessageDialog secondDialog = new MessageDialog("This is the second dialog");
secondDialog.Commands.Add(new UICommand("OK"));
await secondDialog.ShowAsync();
}
This is the correct way to do it:
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
MessageDialog dialog = new MessageDialog("Press ok to show new dialog");
UICommand okCommand = new UICommand("OK");
UICommand cancelCommand = new UICommand("Cancel");
dialog.Commands.Add(okCommand);
dialog.Commands.Add(cancelCommand);
IUICommand response = await dialog.ShowAsync();
if( response == okCommand )
{
MessageDialog secondDialog = new MessageDialog("This is the second dialog");
secondDialog.Commands.Add(new UICommand("OK"));
await secondDialog.ShowAsync();
}
}
Quite simple actually, I should have get this earlier...

Categories