I am trying to create a search box on Ribbon bar of my application.
It should search for given text in a tree control, on hitting Enter button, but without loosing it's focus/selection.
Currently when I am hitting enter it loses it's focus, and makes user to click in that search box again in order to continue.
My search box is a CMFCRibbonEdit control.
Can anyone help?
Thanks in advance.
Had the same problem, and the solution is a bit painful. If you look at the source for CMFCRibbonEdit you'll see it has a protected member CMFCRibbonRichEditCtrl* m_pWndEdit; Internally the ribbon code uses m_pWndEdit->SetFocus(); to set focus on the edit control. You can derive a class from CMFCRibbonEdit using something like
class CMyRibbonEdit : public CMFCRibbonEdit
{
public:
void SetFocus()
{
m_pWndEdit->SetFocus();
}
};
but it has problems. Notably setting the focus calls the command handler for the edit window, so if you call SetFocus from that function you're liable to hit recursion and a stack fault.
Related
I have added a Global Button with the following code.
public override void Initialize()
{
if (!String.IsNullOrEmpty(Base.PrimaryView))
{
Type primaryViewItemType = Base.Views[Base.PrimaryView].Cache.GetItemType();
PXAction action = PXNamedAction.AddAction(Base, primaryViewItemType, "SubmitTicket", "Submit Ticket", TestClick);
}
}
public IEnumerable TestClick(PXAdapter adapter)
{
throw new PXException("Button clicked from graph" + Base.GetType().Name);
}
And it renders the button like this in each of the pages.
Now, I would like to display a popup panel, on button's click. I know I can create a popup panel on screen section. But, is there some way that I can have a general popup panel created in one place and can be displayed on each of the pages on the button's click?
Thank you.
As #HB_ACUMATICA mentioned there is no good easy way.
Providing another alternative to his post, you can create a graph and use it as a reusable popup by calling:
throw new PXPopupRedirectException(graph, string.Empty, true)
One thing I ran into was a sizing issue on the popup...
Changing the height/width when calling another graph as an in-page popup using PXPopupRedirectException
If you do copy and paste the PXSmartPanel you can create re-usable business logic by implementing the reusable business logic pattern found in this help as a starting point:
Reusing Business Logic
If I understand correctly you want to share the same PXSmartPanel control in different pages without having to copy/paste it in every screen.
In Acumatica Framework this is achieve by custom container controls like 'PXUploadDialog' which derives functionality from other controls like 'PXSmartPanel'. This is the control that is used when you attach files in all screen.
Unfortunately there seems to be no documentation on how to achieve this.
The closest I found is this SO question which is essentially unanswered:
Create custom User Control for Acumatica
Considering this, you may want to copy/paste the same smart panel in all screen.
To ease copying you can use the 'Edit ASPX' feature, make sure you backup the project before.
Edit ASPX to get to the code:
Copy paste your smart panel in the page and click 'GENERATE CUSTOMIZATION SCRIPT' to package the changes in the project:
I have added a User Control to my project. After having added it, I have extended it to the "tabPage" class (since I want it to be a tabPage):
public partial class userParPage : TabPage
{
...
}
Since that moment the designer got a "strange" look. Here's a picture:
It doesn't matter where I place the label and the textbox, I am not able to change their size/position etc.
Does anyone know how to reset the normal designer?
I think I have found a work-around.
Change the class from tabPage to UserControl. The Winform designer will display as usual;
Make your changes to the form;
When it's done, re-change the class from UserControl to tabPage.
Like this, you will be able to build up visually your custom user control and to give it a specific type (such as tabPage) just after.
This issue is in the same application as my last question.
I'm experiencing some "odd" behavior, and I don't know if it's functioning as designed or if there's something wrong. In the 3rd party application that I'm "injecting" data into I experience different behavior when I manually edit a record vs. when my automated application edits a record.
If I run the 3rd party application and manually edit a record, the 'Save' and 'Undo' buttons in the toolbar become enabled once I begin typing in a field.
If I run the 3rd party application, then run my automated application to edit a record, my application sets focus to the first field on the form, then "injects" the data into the fields (it actually looks like someone is typing it in very fast) but the 'Save' and 'Undo' buttons stay disabled the whole time. I try to invoke the 'Save' button when I reach the bottom of the form, but I receive an error:
"An unhandled exception of type 'System.Windows.Automation.ElementNotEnabledException' occurred in UIAutomationClient.dll
Additional information: The operation is not allowed on a nonenabled element."
I used this code example on MSDN to insert text in the textboxes of the 3rd party application.
if (!element.TryGetCurrentPattern(
ValuePattern.Pattern, out valuePattern))
{
// Set focus for input functionality and begin.
element.SetFocus();
// Pause before sending keyboard input.
Thread.Sleep(100);
// Delete existing content in the control and insert new content.
SendKeys.SendWait("^{HOME}"); // Move to start of control
SendKeys.SendWait("^+{END}"); // Select everything
SendKeys.SendWait("{DEL}"); // Delete selection
SendKeys.SendWait(value);
}
// Control supports the ValuePattern pattern so we can
// use the SetValue method to insert content.
else
{
// Set focus for input functionality and begin.
element.SetFocus();
((ValuePattern)valuePattern).SetValue(value);
}
Perhaps I'm not searching the correct keywords, but Google has not been much help to me, and I only found one SO post that seemed related. If anyone can shed some light on this I'd really appreciate it.
TIA
UPDATES:
Re: why don't I check if button is enabled...
I don't know how to accomplish that, I was trying to do that earlier today. I have an AutomationElement that references the 'Save' button, but the AutomationElement doesn't have an Enabled property.
AutomationElement toolbar = _mainWindow.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "59392"));
AutomationElement saveButton = toolbar.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Commit Changes (CTRL S)"));
I tried to cast the AutomationElement as Button to check the Enabled property but I receive a build error "Cannot convert type 'System.Windows.Automation.AutomationElement' to 'System.Windows.Forms.Button'"
if (!((Button)saveButton).Enabled)
((Button)saveButton).Enabled = true;
...ok, more searching lead to this: UIAutomation Button Style Enabled
so now I can check if it is enabled, but I haven't figured out how to enable it yet.
2014.10.02 - I think it's not possible to enable a disabled button via UIAutomation. So I will modify my question a bit. If I manually click on an input field and begin typing the 'Save' button becomes enabled. If I use UIAutomation to modify the record the 'Save' button does not become enabled. So, how can I use UIAutomation to get the window into the same state that it's in when I manually edit the record?
You could try using the win32 api to send messages to the button directly. You can get all the handles you need from uiautomation just use the post message function like this.
public TestSetup AutomationLibrary;
[DllImport("User32.dll")] //http://msdn.microsoft.com/en-us/library/windows/desktop/ms644944(v=vs.85).aspx
public static extern int PostMessage(IntPtr hWnd, int uMsg, IntPtr wParam, IntPtr lParam);
public int WM_ENABLE = 0x0A;
public int WM_COMMAND = 0x111;
public MainWindow()
{
InitializeComponent();
AutomationLibrary = new TestSetup();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
AutomationElement aeDesktop = AutomationLibrary.GetDesktop();
AutomationElement aeForm1 = AutomationLibrary.GetAutomationElement("Form1", aeDesktop);
AutomationElement aeDisabledButton = AutomationLibrary.GetAutomationElement("DISABLED", aeForm1);
IntPtr windowIntPtr = new IntPtr(aeForm1.Current.NativeWindowHandle);
IntPtr controlIntPtr = new IntPtr(aeDisabledButton.Current.NativeWindowHandle);
PostMessage(windowIntPtr, WM_COMMAND, (IntPtr)WM_ENABLE, controlIntPtr);
}
The TestSetup is my own home brewed automationlibrary but basically I am just getting automation elements then using the PostMessage function from User32.dll to enable the button. although it doesnt seem to actually enable the button, it does have the unintend consequence of clicking the button.
I used this article as reference for the postmessage function http://www.codeproject.com/Articles/487938/Re-Active-Disabled-Controls
Hope this helps
Using MS VC, I've created a "Dialog based" MFC Application. Let's call it MyApp1. I simply want to add some kind of "box" to my dialog to display text. I tried to add an "Edit Control" and then printing to it via
var_set.SetCueBanner(_T("Test"), TRUE);
var_set is the variable of the Edit Control CEdit. This code is added in a function that is called when pressing a button in the dialog. E.g.
void MyApp1Dlg::OnBnClickedButton1()
{
var_set.SetCueBanner(_T("Test"), TRUE);
}
However, I think this is at least not the way an "Edit Control" should be used... So I tried with a "Static Text". To control it, I read to use
HWND hwndText = GetDlgItem(dlg, IDC_STATIC);
SetWindowText(hwndText, L"Test");
But I would have to use the ID of the dialog dlg which is not defined in MyApp1Dlg.cpp file. I found it in the MyApp1.cpp. Should I export that instance to MyApp1Dlg.cpp or is there another way to display text in my dialog? In the final application, I'd like to use it similar to a
printf("output: %g\n", xx);
command. Thanks for hints.
The SetCueBanner function is for setting a prompt into the edit control. If you want to set the actual text, use SetWindowText - it's part of the parent class CWnd so you would not find it in the CEdit documentation. This works for both edit and static controls, although a static control might also need a RedrawWindow before it shows the new text.
var_set.SetWindowText(_T("Test"));
OK, I got an answer:
First, define an "Edit Control" box. Let's call the ID IDC_EDIT1. Next, in one of the MyApp1Dlg.cpp functions, insert
CString str;
str.Format(_T("%d x %d"), .5, .4);
SetDlgItemText(IDC_EDIT1, str);
and mark the property "Read only" to True.
When I move to a CEdit control on my dialog using the tab key or the arrow keys all the text in the control is selected. This behaviour is causing me problems and I would prefer it if the control just put the cursor at the start (or end) of the text and didn't select anything.
Is there a simple way to do this (e.g. a property of the control that I can set)?
Another way of achieving your goal is to prevent the contents from being selected. When navigating over controls in a dialog the dialog manager queries the respective controls about certain properties pertaining to their behavior. By default an edit control responds with a DLGC_HASSETSEL flag (among others) to indicate to the dialog manager that its contents should be auto-selected.
To work around this you would have to subclass the edit control and handle the WM_GETDLGCODE message to alter the flags appropriately. First, derive a class from CEdit:
class CPersistentSelectionEdit : public CEdit {
public:
DECLARE_MESSAGE_MAP()
afx_msg UINT OnGetDlgCode() {
// Return default value, removing the DLGC_HASSETSEL flag
return ( CEdit::OnGetDlgCode() & ~DLGC_HASSETSEL );
}
};
BEGIN_MESSAGE_MAP( CPersistentSelectionEdit, CEdit )
ON_WM_GETDLGCODE()
END_MESSAGE_MAP()
Next subclass the actual control. There are a number of ways to do this. To keep things simple just declare a class member m_Edit1 of type CPersistentSelectionEdit in your dialog class and add an appropriate entry in DoDataExchange:
// Subclass the edit control
DDX_Control( pDX, IDC_EDIT1, m_Edit1 );
At this point you have an edit control that doesn't have its contents auto-selected when navigated to. You can control the selection whichever way you want.
I don't think that such a style exists.
But you can add OnSetfocus handler with the wizard:
void CMyDlg::OnSetfocusEdit1()
{
CEdit* e = (CEdit*)GetDlgItem(IDC_EDIT1);
e->SetSel(0); // <-- hide selection
}
Please note that there must be a code in your program to highlight the selection. Please find something like this:
CEdit* pEdit = ((CEdit*)GetDlgItem(IDC_EDIT1));
pEdit->SetFocus();
pEdit->SetSel(0, -1); // select everything
Simply comment the last two lines, instead of >SetSel(0). Your code is enabling and disabling which is meaningless to me.