I'm trying to use two devExpress checkedComboBoxes (boxes) to maintain a list and its antilist (i.e, same items in both comboboxes, and they must be checked in only one of the lists).
I'm using C++/CLI, so for each box I handle
EditValueChanged += gcnew System::EventHandler(this, &SelectionControl::exclBox_EditValueChanged);
which calls through to
void
box_ToggleAntibox(
DevExpress::XtraEditors::CheckedComboBoxEdit^ box,
DevExpress::XtraEditors::CheckedComboBoxEdit^ antibox )
{
using namespace DevExpress::XtraEditors::Controls ;
cli::array<String ^> ^ sAnti = gcnew cli::array<String ^>(2*box->Properties->Items->Count) ;
int ii = 0;
String ^ delim = ", ";
for each (CheckedListBoxItem^ i in box->Properties->GetItems()) {
if (i->CheckState==Windows::Forms::CheckState::Unchecked)
{
sAnti[ii] = i->Value->ToString();
++ii;
sAnti[ii] = delim;
++ii;
}
}
String ^ result = String::Concat(sAnti);
antibox->EditValue = result;
}
As the devExpress documentation seems to say to set the edit value, rather than simply iterating through the box list and setting the anti-list to !Checked.
However, it doesn't seem to be working (the correct items are added to the text window, but nothing is checked). Moreover, if I look at my box after the event has finished, I find that the string value in the text window is correct (reflects what I'd selected), but if I open it up, then all items are selected.
Does anyone have any suggestions I might try?
Is it better to set each item's CheckState::Checked instead?
Thanks!
I spent some time talking to DevExpress support. The short answer is that this should work - but doesn't for us. Your mileage may vary, but our solution was to put the two comboboxes on to separate controls on the form.
Related
I have an MFC SDI application to display a list of data read from a csv file. So I set up its view to be inherited from CListView and make it a virtual list control. That means I have to use LVS_OWNERDATA as one of its CListCtrl style attributes. Yet I now run into a problem when I have to include Checkboxes in each row of the displayed list. As you might know, LVS_EX_CHECKBOXES can't be used with LVS_OWNERDATA, I therefore create a bitmap file to contain 2 small images of checkbox (selected and de-selected) and toggle them every time the user clicks on the loaded image/icon. I am handling this in OnNMClick method. And I have two problems I would like to ask for your help to solve.
(1) I don't know how to update the virtual list (which is commonly handled in OnLvnGetdispinfo method) so I try this in OnNMClick and find that the check and unchecked images aren't toggled.
void CMFCSDITest::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
LVHITTESTINFO hitinfo;
hitinfo.pt = pNMItemActivate->ptAction;
int nItem = pListCtrl->HitTest(&hitinfo);
if (hitinfo.flags != LVHT_ONITEMICON)
return;
NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
LV_ITEM* pItem = &(pDispInfo)->item;
if (pItem->iImage == 0)
pItem->iImage = 1;
else
pItem->iImage = 0;
pListCtrl->SetItem(pItem);
pListCtrl->UpdateWindow(); //this is wrong as nothing seems updated after all.
}
Given that the created imagelist is inserted into the pListCtrl already (in OnInitialUpdate method) and I set the output image index value in OnLvnGetdispinfo method.
(2) Instead of handling OnNMClick, I read somewhere people's advice that OnLvnItemchanged method could also be used. However in LPNMLISTVIEW struct, there is uNewState and uOldState variable members for which I don't know how to set up my tiny checked and unchecked icons as status images. Because I might have to do this
if (pNMLV->uChanged & LVIF_STATE)
{
switch (pNMLV->uNewState & LVIS_STATEIMAGEMASK)
{
case image1://do
case image2://do
}
}
DevExpress builds combo boxes in a very odd way. The standard identification built in to Selenuim and Watir (including Page Objects) does not see it as a Select List.
So how can you automate these successfully?
So as it turns out, DevExpress builds combo boxes as a text box with several layered tables associated with it but not under the text box in the HTML tree.
interactions are all done via embedded scripts.
I found the simplest way to automate this object is to identify the text box and the lowest table containing the list of items (3rd table down).
for example (using Watir and Page Objects)
table(:list,:id => 'ComboBoxValue_DDD_L_LBT')
text_field(:state, :id => 'ComboBoxValue_I') #:name => 'State')
I have not found a way to get better IDs at these levels, but we are working that issue.
Then your select code looks like this:
self.state_element.click
row = list_element.find { |row| row[0].text == value }
row.click
Note that with Selenium, you can execute arbitrary javascript in the client to query and set the control's state (if the client-side is enabled for the control). Here's how I did so to extract (and set) the selected text from a combobox named localeSelectList:
// unit test code, c#
[TestMethod]
public void SomeTestMethod()
{
IWebDriver ff = new FirefoxDriver();
ff.Navigate().GoToUrl(homeUrl);
// find the element as an iWebElement
IWebElement localeBox = ff.FindElement(By.CssSelector("#localeSelectList"));
Assert.IsTrue(localeBox.Enabled);
// get the text from the control via javascript
var locale = Util.GetControlText(ff, localeSelectList);
Assert.IsTrue(locale == "English");
// set the text in the control via javascript
Util.SetControlText(ff, localeSelectList, "German");
// verify the text was set
locale = Util.GetControlText(ff, localeSelectList);
Assert.IsTrue(locale == "German");
}
// helper methods, Util class
static public string GetControlText(IWebDriver driver, string controlName)
{
string script = string.Format("return {0}.GetText();", controlName);
var controlText = ((IJavaScriptExecutor)driver).ExecuteScript(script);
return controlText.ToString();
}
static public void SetControlText(IWebDriver driver, string controlName, string controlText)
{
string script = string.Format("{0}.SetValue('{1}');", controlName, controlText);
((IJavaScriptExecutor)driver).ExecuteScript(script);
}
It's not quite the same thing as interacting with the extensions via primitives (clicks, keystrokes, etc) as it won't fire the event handlers for these events, but if your extension uses 'valueChanged' events instead of primitive handlers it's pretty close to the same.
Also note: you can use client-side javascript to find and return elements using jquery/css selectors and ids, as follows:
IWebElement element = (IWebElement) ((IJavaScriptExecutor)driver).ExecuteScript("return $('#.myElementId');")
That's right with several layered tables, but I would like to add that they are only visible when combobox is clicked. First
var cmbParameterGruppen = webDriver.FindElement(By.Id("phContent_ParameterGruppenComboBox_I"));
cmbParameterGruppen.Click();
and then
var tblItems = webDriver.FindElement(By.Id("phContent_ParameterGruppenComboBox_DDD_L_LBT"));
var parameterGruppen = tblItems.FindElements(By.XPath(".//*"));
var count = parameterGruppen.Count;
Debug.WriteLine($"Count = {count}");
if(count > 0)
parameterGruppen[count - 1].Click();
I select hier last row.
I want to create a scoring system. I have 4 buttons with 4 different but similar scripts and want to share 1 GUI Text for the scores. Example Code:
var something : Sprite;
var SpriteRenderer : SpriteRenderer;
var score : int = 0;
var guiScore : GUIText;
function OnMouseDown () {
if(SpriteRenderer.sprite == something) {
score += 1;
guiScore.text = "Score: " = score;
}
}
Right now, if I pressed a button and got a point then I pressed a different button the score would start from 0 again. How can I share data something like static variables but different scripts? I know this sounds a bit noobie but any help would be much appreciated. Thanks in advance
Static variables won't appear in the inspector so you can't assign the GUIText in the inspector (thanks for making me find out). So try using GetComponent instead:
// make a variable of type GUIText
var guiScore: GUIText;
// assign the gameobject in the inspector
var staticObject: GameObject;
// Again I don't know the name of your script, so I'll name it StaticScript
// get the script
StaticScript scr = staticObject.GetComponent(StaticScript);
// assign local GUIText with the one from above
guiScore = scr.guiScore;
This way you have already shared 1 GUIText for all other scripts.
However you said:
Right now, if I pressed a button and got a point then I pressed a
different button the score would start from 0 again
Doesn't that mean something is wrong with the score, not the GUIText?
So I've coded a VSTO addin using vb.net to add a header to a document in Word however from historical methods we have lots of templates with field codes. My addin does not account for these and simply strips the header to add xxxxx value you choose from the pop up.
I need my code to be smart enough to 'spot' the field code and append or if it does not exist e.g. a blank document then continue running as expected. I can append this field code using the below code:
wordDocument.Variables("fieldname").Value = "xxxx"
wordDocument.Fields.Update
However my tool then adds the header as normal and strips most the content from the template. So effectively my question is how would I code a check for this before proceeding. So in plain English I would need my addin to go from this:
Load pop up
Set xxxx value in header
Close
To this:
Load pop up
Check Document for existing "fieldname"
If "fieldname" exists then
wordDocument.Variables("fieldname").Value = "xxxx" (from pop up selection)
wordDocument.Fields.Update
However if "fieldname" doesn't exist then continue as normal....
Sorry if this is a little complex and/or long winded.
Thanks in advance.
Here is my code in C#, hope this might help you to code in VB.Net
foreach (Section sec in doc.Sections)
{
doc.ActiveWindow.View.set_SeekView(WdSeekView.wdSeekCurrentPageHeader);
foreach (HeaderFooter headerFooter in sec.GetHeadersFooters())
{
doc.ActiveWindow.View.set_SeekView(headerFooter.IsHeader ? WdSeekView.wdSeekCurrentPageHeader : WdSeekView.wdSeekCurrentPageFooter);
if (headerFooter.Range.Fields.Count > 0)
{
//Append to existing fields
UpdateFields(headerFooter.Range.Fields);
}
else
{
//Add field code
AddFieldCode(headerFooter.Range);
}
}
doc.ActiveWindow.View.set_SeekView(WdSeekView.wdSeekMainDocument);
}
Extension method to iterate through the header types
public static IEnumerable<HeaderFooter> GetHeadersFooters(this Section section)
{
List<HeaderFooter> headerFooterlist = new List<HeaderFooter>
{
section.Headers[WdHeaderFooterIndex.wdHeaderFooterPrimary],
section.Headers[WdHeaderFooterIndex.wdHeaderFooterFirstPage],
section.Headers[WdHeaderFooterIndex.wdHeaderFooterEvenPages],
section.Footers[WdHeaderFooterIndex.wdHeaderFooterPrimary],
section.Footers[WdHeaderFooterIndex.wdHeaderFooterFirstPage],
section.Footers[WdHeaderFooterIndex.wdHeaderFooterEvenPages]
};
return headerFooterlist;
}
I have a view that displays several nodes. I want to place node form below each displayed node. Both node_add and drupal_get_form directly in template.php works fine, but I get forms with same form ID of NODETYPE_node_form and validation and submitting does not work as expected.
If you had to put several node forms on one page, what would be your general approach?
Progress so far...
in template.php while preprocessing node
$author_profile and $content is set before.
$unique = $vars['node']->nid;
$node = new StdClass();
$node->uid = $vars['user']->uid;
$node->name = $vars['user']->name;
$node->type = 'review';
$node->language = '';
$node->title = t('Review of ') . $vars['node']->realname . t(' by ') . $vars['user']->realname . t(' on ') . $content->title;
$node->field_review_to_A[0]['nid'] = $nodeA->nid;
$node->field_review_to_B[0]['nid'] = $vars['node']->nid;
$node->field_review_to_profile[0]['nid'] = $author_profile->nid;
if(!function_exists("node_object_prepare")) {
include_once(drupal_get_path('module', 'node') . '/node.pages.inc');
}
//$vars['A_review_form'] = drupal_get_form('review_node_form', $node);
$vars['A_review_form'] = mymodule_view($node, $unique);
in mymodule module
function mymodule_view($node, $unique) {
if(!function_exists("node_object_prepare")) {
include_once(drupal_get_path('module', 'node') . '/node.pages.inc');
}
$output = drupal_get_form('review_node_form_' . $unique, $node);
return $output;
}
function mymodule_forms($form_id, $args) {
$forms = array();
if (strpos($form_id, "review_node_form_") === 0) {
$forms[$form_id] = array('callback' => 'node_form');
}
return $forms;
}
function mymodule_form_alter(&$form, $form_state, $form_id) {
if (isset($form['type']) && isset($form['#node']) && $form_id != $form['type']['#value'] .'_node_form' && $form['type']['#value'] == 'review') {
$type = content_types($form['#node']->type);
if (!empty($type['fields'])) {
module_load_include('inc', 'content', 'includes/content.node_form');
$form = array_merge($form, content_form($form, $form_state));
}
$form['#pre_render'][] = 'content_alter_extra_weights';
$form['#content_extra_fields'] = $type['extra'];
//$form['#id'] = $form_id;
//$form['#validate'][0] = $form_id . '_validate';
$form['title']['#type'] = 'value';
$form['field_review_to_A']['#type'] = 'value';
$form['field_review_to_B']['#type'] = 'value';
$form['field_review_to_profile']['#type'] = 'value';
}
}
Questions
My take on summarizing unclear questions...
Is this good general approach for displaying multiple node forms on same page?
Is it OK to copy/paste code from content modules content_form_alter function in function mymodule_form_alter? Will it not brake things if content module is updated?
Should i set $form['#id']? Without it all forms has same HTML form ID of node_form, with it ID is unique, like review_node_form_254. Thing is that there is no difference of how form is submitted. Setting $form['#validate'][0] does not seem to influence things too. Maybe I should set $form[button]['#submit'][0] to something else? Now its node_form_submit.
Why validation does not work even with unique form id and form validate function? If i submit last form without required field all previous forms gets particular fields red. should I make my own validation function? what level - form or field? Any tips on where to start?
You need to implement hook_forms() to map different ids to the same builder function.
The NODETYPE_node_form ids you mention are already an example of this mechanism, as they are all mapped to the same builder function (node_form()) within the node modules node_forms() implementation.
You can find links to more examples in the 'Parameters' explanation off the drupal_get_form() function.
This was exceptionally useful to me.
Documentation on all the drupal APIs is so lacking - I was tearing my hair out. The crucial bit for me, that I don't think is covered anywhere else on the net:
CCK adds its fields to your form through hook_form_alter() . But it does this based on the form_id. So if the form ID is different (cause you want multiple ones on the same page), you need to replicate a bit of the CCK code to add the fields to your form regardless.
That is what this does brilliantly.
I really did not dig to the bottom of it, but it seems to me that you pretty much did all the relevant digging by yourself.
From what I understand by inspecting the code only, you are right in thinking that content_form_alter() is the show-stopper.
Maybe this is a naïve suggestion, but what about writing your own implementation of hook_form_alter() starting from the content_form_alter() code but changing the conditions that make the alteration to occur? I am thinking to something along these lines:
function modulename_form_alter(&$form, $form_state, $form_id) {
if (isset($form['type']) && isset($form['#node']) &&
stripos($form_id, $form['type']['#value'] .'_node_form')) {
...
}
}
I did not actually test the code above, but I hope it is self-explenatory: you actually trigger the changes for a give customised type of content if MYCCKTYPE_node_form is a substring of the actual form_id (es: MYCCKTYPE_node_form_234).
Hope this helps at least a bit... Good luck! :)
EDIT: TWO MORE THINGS
It just occurred to me that since your custom implementation of hook_form_alter() will live aside the CCK one, you would like to add a check to avoid the form to be modified twice something like:
&& $form_id != $form['type']['#value'] .'_node_form'
The other way you might try to implement this by not using CCK but implementing you custom type programmatically (this might even be an advantage if you plan to use your module on various different sites).