Using of RaiseCanExecuteChanged - delegatecommand

I make two methodes like this:
private void Next(string argument)
{
Current = Clients[Clients.IndexOf(Current) + 1];
((DelegateCommand)NextCommand).RaiseCanExecuteChanged();
}
private void Previous(string argument)
{
Current = Clients[Clients.IndexOf(Current) - 1];
((DelegateCommand)PreviousCommand).RaiseCanExecuteChanged();
}
and bind to the xaml:
Every thing work fine. And the next button becomes inactive/grey out when it hits the last post.
The problem is it (the Next button) still inactive when I click the Previous button. The Next button becomes inactive all the time.
My question is how I could make the Next button active again? Thank for all help.

I assume you are talking about a WPF Application.
There are several reasons your button could become / stay inactive:
Your CanExecute implementation is faulty and returns false even if it should return true
You didnt implement CanExecute or didnt hook it up correctly
The CommandManager didn't realize it's time to requery the commands
You've got a problem with the Focus on your Window / Control
You need to show more of the code so it gives us a broader picture of what you are trying to do.

Related

Cannot enable a Ribbon button programmatically

I developed a VSTO 4 add-in for Excel. It works perfect, however, I have a button placed in the custom tab of its Ribbon control that is initially disabled.
After clicked other ribbon button in my custom tab, I need to enable the initially disabled button.
I tried with:
btnCancelar.Visible = true;
In the Click event of a button, but button is not shown. The strange thing is that when debugging, it still does not appear, but if a MessageBox is shown, the button get visible at last.
I don't understand this behaviour. How can I enable or disable a ribbon button dynamically by code?
I'm not sure what your language is used in your project, but I guess you can tranform it to your own language used. I'll show the example here in C#:
First you need to implement a so called Callback function in the RibbonXML definition:
<button id="buttonSomething" label="Content" size="large" getVisible="EnableControl"/>
then the next step is to implement the Callback function:
public bool EnableControl(IRibbonControl control)
{
return true; // visible ... false = invisible
}
VSTO will trigger the getVisible Callback and depending on the return value enable or disable the visible state (don't forget to remove any Visible property from the RibbonXML, otherwise the Callback is not triggered)
In case of the Ribbon Designer you need to make sure your Click signature is correct, the easies way to do that is by double clicking the button on the ribbon designer. This will create the Click method for you, for instance:
I created a Ribbon with the Ribbon designer and added two buttons. Double clicked the first button to get an empty method like below, and added the code.
private void button1_Click(object sender, RibbonControlEventArgs e)
{
// Toggle button visibility and make sure the button is enabled
// Visible (obviously) makes it visible, while Enabled is grayed if
// false. You don't need this it is Enabled by default, so just for
// demo purposes
button2.Visible = !button2.Visible;
button2.Enabled = button2.Visible;
// Force Ribbon Invalidate ...
this.RibbonUI.Invalidate();
// Long running proces
}
This worked perfectly for me, so if it doesn't work for you please provide more details of your coding.
I have created a workaround to this.
It was simple. Just started the long running process in different thread. That way, cancel button is shown when it should and then hidden after the process ends.
I used this code to launch the process in the Ribbon.cs code:
btnCancelar.Visible = true;
Action action = () => {
Formatter.GenerateNewSheet(Formatter.TargetType.ImpresionEtiquetas, frm.CustomerID, workbook, btnCancelar);
};
System.Threading.Tasks.Task.Factory.StartNew(action);
And inside the process method I have this code:
public static bool GenerateNewSheet(TargetType type, string customerID, Excel.Workbook workbook, Microsoft.Office.Tools.Ribbon.RibbonButton btnCancelar)
{
try
{
_cancelled = false;
InfoLog.ClearLog();
switch (type)
{
case TargetType.ImpresionEtiquetas:
return GenerateTagPrinting(customerID, workbook);
}
return false;
}
finally
{
btnCancelar.Visible = false;
}
}
The interesting thing here I have discovered is that Excel is thread safe, so it was not necessary to add a synchronization mechanism neither when adding rows in the new sheet nor when setting Visible property to false again.
Regards
Jaime

Custom context menu XAML for WP8

I try to implement a custom ContextMenu in a LongListSelector.
I'm not using the ContextMenu from Microsoft.Phone.Controls.Toolkit, it's basically the same as in the Rowi App:
(source: hiddenpineapple.com)
Approach 1
My list item toggles a VisualState on hold and an overlay is shown with controls in it.
The problem
I can't find a way to go back to the default state when the user clicks outside of the list item (as in the default ContextMenu).
Approach 2
I've implemented a custom template for the toolkit ContextMenu which looks exactly the same. I had to move its margin top to -itemHeight, as by default it is below the item.
The problem
The problem with this solution is, that it automatically closes itself when opening and I couldn't figure out how to avoid this.
Another problem was that it didn't work well with TiltEffect.IsTiltEnabled from the Toolkit (visual problems).
I need your help
Any suggestions on how to get this working?
Answer
Thanks to Cheese, now I know how to properly close the menu when the user clicks outside.
His suggestion was to get the coordinates of a Tap event on the current page, and check if it's inside the menu. When not, close the menu.
So I added a Tap listener to the page when the menu opens, and removed it when the menu closes. From the page listener I got the event coordinates and could check if it's inside the control which holds the menu (same size and position). I received the position of the control with Point leftUpperPoint = control.TransformToVisual(page).Transform(new Point(0, 0)) and the rightLowerPoint by adding the ActualWidth and ActualHeight.
But then I realized:
Why should I even calculate if the tap is inside the menu? I always want to close the menu when the user taps anywhere on the screen. If it's outside, yes. If it's on a menu button, yes.
Another modification I made was to listen for MouseLeftButtonDown instead of Tap as it also triggers when the user swipes.
So I removed this code and came up with the following:
private void ToggleMenu(object sender, System.Windows.Input.GestureEventArgs e)
{
PhoneApplicationFrame frame = ((PhoneApplicationFrame)Application.Current.RootVisual);
VisualState state = this.States.CurrentState;
if (state == null || state.Name == "DefaultState")
{
frame.MouseLeftButtonDown += MouseDownDelegate;
this.State = "MenuState";
}
else
{
frame.MouseLeftButtonDown -= MouseDownDelegate;
this.State = "DefaultState";
}
}
private void MouseDownDelegate(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
ToggleMenu(sender, null);
}
This works perfectly!
Thanks to Cheese for the hint.
Something like this by #denniscode http://dotnet.dzone.com/articles/rowi-show-tap-menu
Approach 1 problem
The best solution would be:
Get the menus coordinates, when user makes a tap - you check are tap coordinates on menu or not, if not - dissmiss - simple.
Approach 2 problem
I guess you had some button in a corner and when you tapped on it - nothing happened? And when you dissmissed the Tilt all worked. It seems that tilt works faster than a click, so, tilt changes the button coordinates, and device thiks you have missed/or dragged off
You can use what #ScottIsAFool suggested and maybe create another Dependency Property on your TapMenu control of type UIElement named CloseWhenTappedElement and automatically listen for Tap events inside your control once set. For example
<Grid x:Name="TapArea"/>
<TapMenu CloseWhenTappedElement="{Binding ElementName=TapArea"}/>

showandwait changing variable value

I'm having a problem with a variable I'm using to track the status of a user activity. In a GUI I have a button that, on clicking the button launches a second GUI. In that GUI, the user can either complete the activity started in the first GUI or not.
If the user cancels the second GUI, then the idea is to go back to the first GUI, leaving all variables and lists with their current values. If the second GUI completes the activity of the first GUI, then all variables and lists should be reset.
To track this, I have a variable (Boolean complete) initially set to FALSE. In the second GUI, when the "OK" button is clicked (rather than the "Cancel" button), the second GUI calls a method in the first GUI, changing the value of "complete" to TRUE.
To see what the heck is going on, I have System.out.println at several points allowing me to see the value of "complete" along the way. What I see is this:
Launching first GUI - complete = FALSE
Launching second GUI - complete = FALSE
Clicking "OK" in second GUI - complete = TRUE
Second GUI closes itself, returning to complete first GUI activity
First GUI finishes activity with complete = FALSE
I'm assuming it is because I am launching the second GUI with a showandwait, and when the method containing the showandwait begins, the value of "complete" = FALSE. The value changes in the WAIT part of show and wait, then the method continues and that is where I get the value still being FALSE, though it was changed to TRUE.
Here is a summary of the code in question (if you need exact code, it's longer, but I can post on request):
completeButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
try {
System.out.println("b4 calc = " + complete); // complete = FALSE
// all the code to create the calcStage
calcStage.showAndWait(); // second GUI, which calls a method in THIS
// class that changes complete to TRUE. That method
// (in THIS file) also has a println that shows the change.
getComplete(); // tried adding this method to check the value of
// "complete" after the change made by the calcStage
// (which calls a method in this same file)
System.out.println("Complete? " + complete);
// this shows complete = FALSE,
// though in the calcStage it was changed to TRUE
if (salecomplete) {
// code that should reset all variables and lists if the activity was completed
}
}
}
}
The question here is why does the second GUI successfully change the value of "complete", but when I return to the first GUI it still sees complete as FALSE? And how can I get around this?
Try having the controller of the second GUI calling a method in the first GUI's controller to modify that complete variable
For example:
// Code to handle the OK button being pressed
#Override
public void handle(ActionEvent t) {
// Do validation and work
//reference to the first controller object
firstController.setComplete(true);
}

CoreDispatcher.ProcessEvents() causes an indirect crash?

I have to port some legacy code, that uses modal dialog boxes all over the place to Metro/WinRT (using C++/CX). Because these dialog boxes provide their own message loop (using DialogBoxParam()), the calling code will wait until the user has clicked a button on the message box.
I'm currently trying to write a replacement for the old message box class, that uses XAML and the popup control. To reproduce the same behavior, I have to wait in the calling thread, but also have to keep the UI responsive. I've found out, that CoreDispatcher::ProcessEvents() can be used in a loop, to keep processing events (yeah I realize that this isn't very beautiful, but I don't want to change all of our legacy code to a new threading model). However I'm running into an issue that keeps crashing my app.
Here is a minimal example that reproduces the issue (just create a XAML app and wire this to a button):
void CPPXamlTest::MainPage::Button_Click_1(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
bool cancel = false;
auto popup = ref new Popup();
auto button = ref new Button();
button->Content = "Boom";
auto token = (button->Click += ref new RoutedEventHandler([&cancel] (Object ^, RoutedEventArgs ^) { cancel = true; }));
popup->Child = button;
popup->IsOpen = true;
while (!cancel)
{
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
popup->IsOpen = false;
button->Click -= token;
}
This seems to work well for the first one or two tries of opening and closing the popup, using the two buttons. After a few tries however, the application will instantly crash deep in Windows.UI.Xaml.dll, while trying to dereference a null pointer. I can also reproduce this in C# (with practically the same code).
Does anyone have an idea, what is going on in here? Or a suggestion for an alternative approach?
If anyone is interested: I asked the same question a few days later on the MSDN forums and got a response there from a Microsoft employee:
http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/11fa65e7-90b7-41f5-9884-80064ec6e2d8/
Apparently the problem here is the nested message loop that is caused by calling ProcessEvents inside an event handler. It seems that this is not supported by WinRT, but instead of failing in a well-defined manner, this will or may cause a crash.
Alas this was the best and only answer I could find, so I ended up working around the problem, by dispatching the event handler (and a lot of other code) into another thread. I could then emulate the waiting behavior of DialogBox()/DialogBoxParam() (outside the main thread), by waiting on an event that was signaled when the user clicked/tapped a button on my XAML "dialog" popup.
A workaround that works fine for me is to replace the line:
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
with:
auto myDispatchedHandler = ref new DispatchedHandler([&](){
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
});
dispatcher->RunAsync(CoreDispatcherPriority::Normal,myDispatchedHandler);
For more info see this post at MSDN.

Windows Forms: Unable to Click to Focus a MaskedTextBox in a Non TopLevel Form

Like the title says, I've got a Child form being shown with it's TopLevel property set to False and I am unable to click a MaskedTextBox control that it contains (in order to bring focus to it). I can bring focus to it by using TAB on the keyboard though.
The child form contains other regular TextBox controls and these I can click to focus with no problems, although they also exhibit some odd behavior: for example if I've got a value in the Textbox and I try to drag-click from the end of the string to the beginning, nothing happens. In fact I can't use my mouse to move the cursor inside the TextBox's text at all (although they keyboard arrow keys work).
I'm not too worried about the odd TextBox behavior, but why can't I activate my MaskedTextBox by clicking on it?
Below is the code that shows the form:
Dim newReportForm As New Form
Dim formName As String
Dim FullTypeName As String
Dim FormInstanceType As Type
formName = TreeView1.SelectedNode.Name
FullTypeName = Application.ProductName & "." & formName
FormInstanceType = Type.GetType(FullTypeName, True, True)
newReportForm = CType(Activator.CreateInstance(FormInstanceType), Form)
Try
newReportForm.Top = CType(SplitContainer1.Panel2.Controls(0), Form).Top + 25
newReportForm.Left = CType(SplitContainer1.Panel2.Controls(0), Form).Left + 25
Catch
End Try
newReportForm.TopLevel = False
newReportForm.Parent = SplitContainer1.Panel2
newReportForm.BringToFront()
newReportForm.Show()
I tried your code and got a good repro this time. As I mentioned in my original post, this is indeed a window activation problem. You can see this in Spy++, note the WM_MOUSEACTIVATE messages.
This happens because you display the form with a caption bar. That convinces the Windows window manager that the window can be activated. That doesn't actually work, it is no longer a top-level window. Visible from the caption bar, it never gets drawn with the "window activated" colors.
You will have to remove the caption bar from the form. That's best done by adding this line to your code:
newReportForm.FormBorderStyle = Windows.Forms.FormBorderStyle.None
Which will turn the form into a control that's otherwise indistinguishable from a UserControl. You can still make it distinctive by using this code instead:
newReportForm.ControlBox = False
newReportForm.Text = ""
Either fix solves the mouse click problem.
This is a miserable bug and it took me a long time to find this question. We're doing exactly the same thing as the OP, displaying a Form inside a split container. My workaround was to add an event handler to the MaskedTextBox's Click event:
private void MaskedTextBoxSetFocus(object sender, EventArgs e)
{
var mtb = (MaskedTextBox)sender;
mtb.Focus();
}
This works for the MaskedTextBox but I'm concerned about other odd behavior due to this bug so I will probably set the border style as in the accepted answer.
The text box behavior is a symptom of the same problem. Something is swallowing mouse down notifications. It isn't explained by your code snippet. Forms indeed swallow the mouse click that activates them, but that is a one-time behavior and is turned off by setting its TopLevel property to False.
Not much left. One candidate is the Control.Capture property, turned on at the MouseDown event for a button so that the button can see the MouseUp event, no matter where the mouse moved. That's a one-time effect as well. Watch out for controls that set the Focus in a MouseDown event.
The other is some kind of IMessageFilter code in your form(s) that's eating WM_LBUTTONDOWN messages.