I took reference from below Ruslan post and implemented same and working as expected but sometimes, am facing an issue saying like "An error occurred during processing of the field ItemRequiresTerms: There is already an open DataReader associated with this Command which must be closed first."
How to show images inside selector lookup?
One Stock Item may have multiple images and we need only icon images.
Below is the code.
public void InventoryItemRowSelecting(PXCache sender, PXRowSelectingEventArgs e)
{
var row = e.Row as InventoryItem;
if (row != null)
{
if (!string.IsNullOrEmpty(row.ImageUrl))
{
foreach (NoteDoc noteDoc in PXSelectReadonly<NoteDoc, Where<NoteDoc.noteID, Equal<Required<NoteDoc.noteID>>>>.Select(Base, row.NoteID)) // here i got error
{
foreach (UploadFile uploadFile in PXSelectReadonly<UploadFile, Where<UploadFile.fileID, Equal<Required<UploadFile.fileID>>>>.Select(Base, noteDoc.FileID))
{
if (uploadFile.Name.Contains("icon"))
{
row.ImageUrl =
ControlHelper.GetAttachedFileUrl(null, uploadFile.FileID.ToString());
break;
}
}
}
}
}
}
You need to use separate connection scope to execute additional BQL statements within a RowSelecting event handler.
More details can be found here.
You can avoid nested for loops by utilizing proper Join,
public void InventoryItemRowSelecting(PXCache sender, PXRowSelectingEventArgs e)
{
var row = e.Row as InventoryItem;
if (row != null)
{
if (!string.IsNullOrEmpty(row.ImageUrl))
{
using (new PXConnectionScope())
{
UploadFile uploadFile = PXSelectReadonly2<UploadFile, InnerJoin<NoteDoc, On<NoteDoc.fileID, Equal<UploadFile.fileID>>>,
Where<NoteDoc.noteID, Equal<Required<NoteDoc.noteID>>,
And<UploadFile.name, Like<Required<UploadFile.name>>>>>.
Select(Base, row.NoteID, "%icon%");
row.ImageUrl = (uploadFile != null) ? ControlHelper.GetAttachedFileUrl(null, uploadFile.FileID.ToString())
: null;
}
}
}
}
Already an accepted answer here, but I wanted to show you an alternative to the deeply indented structure you are using in your example code.
public void InventoryItemRowSelecting(PXCache sender, PXRowSelectingEventArgs e)
{
var row = e.Row as InventoryItem;
if (row == null)
return; // Don't proceed when row doesn't exist
if (string.IsNullOrEmpty(row.ImageUrl))
return; // Don't proceed when ImageUrl doesn't exist
foreach (NoteDoc noteDoc in PXSelectReadonly<NoteDoc, Where<NoteDoc.noteID, Equal<Required<NoteDoc.noteID>>>>.Select(Base, row.NoteID)) // here i got error
{
foreach (UploadFile uploadFile in PXSelectReadonly<UploadFile, Where<UploadFile.fileID, Equal<Required<UploadFile.fileID>>>>.Select(Base, noteDoc.FileID))
{
if (!uploadFile.Name.Contains("icon"))
continue; // Skip non-icon files
row.ImageUrl = ControlHelper.GetAttachedFileUrl(null, uploadFile.FileID.ToString());
}
}
}
Note how you use more the code page instead of pushing everything over to the right. This is your original example, so it doesn't have the fixes from the accepted answer, I just wanted to show you a possible alternate pattern to consider in the future.
This also is a dramatic change when you apply this to the accepted solution:
public void InventoryItemRowSelecting(PXCache sender, PXRowSelectingEventArgs e)
{
var row = e.Row as InventoryItem;
if (row == null)
return; // Don't proceed when row doesn't exist
if (string.IsNullOrEmpty(row.ImageUrl))
return; // Don't proceed when ImageUrl doesn't exist
using (new PXConnectionScope())
{
UploadFile uploadFile = PXSelectReadonly2<UploadFile, InnerJoin<NoteDoc, On<NoteDoc.fileID, Equal<UploadFile.fileID>>>,
Where<NoteDoc.noteID, Equal<Required<NoteDoc.noteID>>,
And<UploadFile.name, Like<Required<UploadFile.name>>>>>.
Select(Base, row.NoteID, "%icon%");
if (uploadFile == null)
continue; // Skip non-icon files
row.ImageUrl = ControlHelper.GetAttachedFileUrl(null, uploadFile.FileID.ToString());
}
}
Related
I have a small problem regarding C# and WindowsForms.
I'm trying to get string SelectedItemName = combobox2.SelectedItem.ToString(); this variable in another class. For example I have this in my Form1.cs Class.
public void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
{
FileIniDataParser fileParser = new FileIniDataParser();
IniData data = fileParser.ReadFile("config.ini");
IniProgram classReference = new IniProgram();
string SelectedItemName = (string)comboBox2.SelectedItem.ToString();
// string _SelectedItemName = (string)comboBox2.SelectedText;
Console.WriteLine(SelectedItemName);
if (comboBox2.SelectedIndex > -1)
{
testvariabel2.GetSessionName();
}
}
And than my other Class CTestRack.cs looks like this:
if (_form1Object.comboBox2.SelectedIndex.ToString() != null)
{
string SelectedItemName = _form1Object.comboBox2.SelectedItem.ToString();
System.Threading.Thread.Sleep(1000);
if (newDictionary.ContainsKey(SelectedItemName))
Now I've tried getting and setting the variable in the Form1 class but I was just getting Loop errors, now with this method I'm getting a NULLReferenceException.
By the way I was already looking into several related posts here in SO but didn't found my answer yet.
My question is just how do I get the active Text from the Combobox in my other Class as a String?
Ensure that _form1Object, is indeed set to the instance of form you want to access... It's hard to tell from above code if correct initialization of _form1Object is the problem here.
Assuming _form1Object, is correctly initialized, one bug in above code is that ComboBox.SelectedIndex property is an int.
See http://msdn.microsoft.com/en-us/library/system.windows.forms.combobox.selectedindex(v=vs.110).aspx
It doesn't matter if there is SelectedItem or not, comboBox2.SelectedIndex.ToString() != null will always be true, but comboBox2.SelectedItem could still be null, and hence comboBox2.SelectedItem.ToString() would fail with NullReferenceException.
It's possible that comboBox2 doesn't have SelectedItem, you can check it
either by
comboBox2.SelectedItem != null
Or by
comboBox2.SelectedIndex >= 0
Something like that
if (comboBox2.SelectedItem != null) {
string SelectedItemName = comboBox2.SelectedItem.ToString();
Console.WriteLine(SelectedItemName);
testvariabel2.GetSessionName();
}
else {
// No selected item in the ComboBox
}
...
if (_form1Object != null)
if (_form1Object.comboBox2.SelectedIndex >= 0) {
string SelectedItemName = _form1Object.comboBox2.SelectedItem.ToString();
System.Threading.Thread.Sleep(1000);
if (newDictionary.ContainsKey(SelectedItemName))
...
}
I have this code where you are suppose to be able to pick specific file attributes, but for some reason it is acting really weird. Can anyone spot the error(s)?
This is in a form, I am triggering checkAttributes when a file is selected. (string)path is the path to the selected file.
private async void Dropdown_File_Attr_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
try
{
foreach (FileAttributes attr in Enum.GetValues(typeof(FileAttributes)))
if (e.ClickedItem.Text == attr.ToString() && !(bool)e.ClickedItem.Tag)
File.SetAttributes(path, File.GetAttributes(path) | attr);
else if (e.ClickedItem.Text == attr.ToString() && (bool)e.ClickedItem.Tag)
File.SetAttributes(path, File.GetAttributes(path) & ~attr);
checkAttributes(path);
await WaitX(5);
Dropdown_File.ShowDropDown();
Dropdown_File_Attr.ShowDropDown();
}
catch (Exception ex) { MessageBox.Show("An error occured:\n\n" + ex.ToString(), "Error"); }
}
public async Task WaitX(int miliseconds) { await Task.Delay(miliseconds); }
private List<string> getAttributes(string ppath)
{
List<string> result = new List<string>();
FileAttributes attrs = File.GetAttributes(ppath);
if ((attrs & FileAttributes.Archive) == FileAttributes.Archive) result.Add("Archive");
if ((attrs & FileAttributes.Compressed) == FileAttributes.Compressed) result.Add("Compressed");
// This goes on for every attribute
return result;
}
private void checkAttributes(string ppath)
{
foreach (string s in getAttributes(ppath))
foreach (ToolStripDropDownItem item in Dropdown_File_Attr.DropDownItems)
{
if (item.Text == s)
{
item.Image = Resources.check;
item.Tag = true; // isChecked
}
else
{
item.Image = Resources.cross;
item.Tag = false; // isChecked
}
}
}
Just an example:
If in the beginning only Normal is selected, and I select Hidden, Hidden is the only one with a cross. If then select ReadOnly, ReadOnly is the only one with a cross but if I check, the file is still Hidden in Windows Explorer.
I have been looking for the error hours. Can anyone please help me (I don't have a lot of experience with Enums and FileAttributes)?
you loop over all items of the dropdown, but act only on the clicked item. you have to check all of the items. and combine their values to construckt the final attribute value, or you'll never catch the automatically cleared item. or just set the one checked attribute, without combining it with the current flags of the file, id you only want to set the one anyway.
as an aside, your logic would work with multi selection, which i'd allow anyway. it makes sense to allow setting a file hidden and readonly, for example.
I want to compare last selected node and current selected node on the treeview by using java script.
Please suggest me with some code samples to compare last selection and current selection node on the treeview.
If both the node selections are same , we need to deselect the same node.
Thanks. Please help on this.
I have resolved by server side code:
protected void TreeView1_PreRender(object sender, EventArgs e)
{
if (TreeView1.SelectedNode != null)
{
if (!string.IsNullOrEmpty(ADUtility.treenodevalue))
{
if (ADUtility.treenodevalue == TreeView1.SelectedNode.ValuePath)
{
TreeView1.SelectedNode.Selected = false;
}
else
{
ADUtility.treenodevalue = TreeView1.SelectedNode.ValuePath;
}
}
else
{
ADUtility.treenodevalue = TreeView1.SelectedNode.ValuePath;
}
}
}
I am just giving you the Pseudo code for this after that you can implement it by own.
Make 2 Global variables CurrentselectedNode and PreviousselectedNode
And make a ArrayList of Nodes
Arraylist<Object> nodeCollection;
var PreviousselectedNode;
var CurrentselectedNode;
if(nodeCollection.Current != null)
{
PreviousselectedNode= nodeCollection.Current;
var tempselectedItem = Products_Data.selectedNodeID.value;
var CurrentselectedNode = Document.getElementById(tempselectedItem);
// Here Do what you want to do with current Node and Previous Node
nodeCollection.Add(tempselectedNode);
}
else
{
var tempselectedItem = Products_Data.selectedNodeID.value;
var tempselectedNode = Document.getElementById(tempselectedItem);
nodeCollection.Add(tempselectedNode);
}
I have a DataGridView that I populate with a file and folder list. I'd like to sort the DataGridView alphabetically, but with all the folders above the files. Here's the general idea:
.\folder1\
.\folder2\
.\folder3\
.\file1
.\file2
I have a column with icons for the different filetypes, so there's a folder icon and file icons. It's the only difference I have between the two columns. Here's a picture:
So you can see that files and folders have different icons. Here is my current sort method:
private void dgvFiles_SortCompare(object sender, DataGridViewSortCompareEventArgs e) {
if(e.Column.Index == 1) {
// ???
}
else if(e.Column.Index == 4) {
string cellValue1 = e.CellValue1.ToString(),
cellValue2 = e.CellValue2.ToString();
if(!string.IsNullOrWhiteSpace(cellValue1) && !string.IsNullOrWhiteSpace(cellValue2)) {
cellValue1 = Regex.Replace(cellValue1, "[^.0-9]", "");
cellValue2 = Regex.Replace(cellValue2, "[^.0-9]", "");
int a = int.Parse(cellValue1), b = int.Parse(cellValue2);
e.SortResult = a.CompareTo(b);
e.Handled = true;
}
}
}
Is it possible to sort the DataGridView this way using a custom SortCompare method? If so, how?
I depends on how you've set the image inside the column but instead of using e.CellValue1 and e.CellValue2 as you have done for the size sorting, use GridName.Rows[e.RowIndex1] and GridName.Rows[e.RowIndex2] to access the underlying data instead.
So what I did instead was I created a class for folder items named FolderItem. I then created a list of these FolderItem objects and populated the DataGridView using the list. It actually made it really easy--I just had to use this snippet of code:
List<FolderItem> items = new List<FolderItem>();
private void dgvFiles_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) {
if(e.ColumnIndex == 1) {
items.OrderBy(i => i.type).ThenBy(i => i.oldName);
items.Reverse(); // to account for ascending/descending order
RefreshDataGridView();
}
}
public void RefreshDataGridView() {
dgvFiles.Rows.Clear();
foreach(FolderItem item in items) {
dgvFiles.Rows.Add(item.icon, item.oldName, item.newName, item.type, item.size, item.created, item.modified);
}
}
(type was null for folders so it occurred above the other items.)
You could also probably find some way to bind the datagridview to the list, but I didn't do that.
I'm using this snippet to analyze the rows I've selected on a datagrid.
for (int i = 0; i < dgDetalle.Items.Count; i++)
{
DataGridRow row = (DataGridRow)dgDetalle.ItemContainerGenerator.ContainerFromIndex(i);
FrameworkElement cellContent = dgDetalle.Columns[0].GetCellContent(row);
// ... code ...
}
The cycle runs smoothly, but when processing certain indexes, the second line throws a null exception. MSDN's documentation says that ItemContainerGenerator.ContainerFromIndex(i) will return null if 'if the item is not realized', but this doesn't help me to guess how could I get the desired value.
How can I scan all the rows? Is there any other way?
UPDATE
I'm using this snippet to read a CheckBox as explained here. So I can't use binding or ItemSource at all unless I change a lot of things. And I cannot. I'm doing code maintenance.
Try this,
DataGridRow row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
grid.UpdateLayout();
grid.ScrollIntoView(grid.Items[index]);
row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
}
The DataGrid is virtualizing the items, the respective rows (i.e. containers) are only created when the row is in view.
You could either turn off virtualization (which makes the first time loading very slow if you have many items, also the memory usage will be higher) or you just iterate over the data and check the values of the data objects' properties which should be bound to the data-grid. Usually you should not need the UI elements at all...
Use this subscription:
TheListBox.ItemContainerGenerator.StatusChanged += (sender, e) =>
{
TheListBox.Dispatcher.Invoke(() =>
{
var TheOne = TheListBox.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem;
if (TheOne != null)
// Use The One
});
};
In addition to other answers: items aren't available in constructor of the control class (page / window / etc).
If you want to access them after created, use Loaded event:
public partial class MyUserControl : UserControl
{
public MyUserControl(int[] values)
{
InitializeComponent();
this.MyItemsControl.ItemsSource = values;
Loaded += (s, e) =>
{
for (int i = 0; i < this.MyItemsControl.Items.Count; ++i)
{
// this.MyItemsControl.ItemContainerGenerator.ContainerFromIndex(i)
}
};
}
}
In my case grid.UpdateLayout(); didn't help an I needed a DoEvents() instead:
DataGridRow row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
WPFTools.DoEvents();
grid.ScrollIntoView(grid.Items[index]);
row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
}
/// <summary>
/// WPF DoEvents
/// Source: https://stackoverflow.com/a/11899439/1574221
/// </summary>
public static void DoEvents()
{
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new DispatcherOperationCallback(
delegate (object f)
{
((DispatcherFrame)f).Continue = false;
return null;
}), frame);
Dispatcher.PushFrame(frame);
}