I did a single cell subscription, so when I put the formula into the cell, it updates it correctly.
Now, I'm returning an object with multiple values and I want to display all of them in Excel cells. Is it possibly to only put a formula in 1A, subscribe once, get all values at once, and then distribute the information from one object to 1A, 1B, 1C... Or is the only way to subscribe individually to each field and put an RTD formula for every cell?
I came up with a workaround using a VBA function. Create your Excel sheet, make column headings that will match the fields that you need, put a formula in your 1A cell, and run the VBA function.
The function is just a for loop over all columns in Range (number of rows is still up to), that just gets the column header value and does your magic and the rest is up to simple string manipulation of getting the formula, converting it to string and replacing $C1 to $D1 etc.
Example:
"=RTD("ProgId", , "Your arbitrary parameter here", $C1)"
Wouldn't say it is the fastest way, but it is a good solution
Related
In my project the argument of one UDF is the result of another UDF function.
For example:
GetPeriod(string name, string date) {
// logic
}
Data(string name, string period) {
// logic
}
I am using these UDF in two different cells as
cell a1: =GetPeriod("KMP", "27-12-18")
cell a3: =Data(a$1,"KMP")
I am using the result of one UDF (GetPeriod) as a parameter in another UDF(Data).
The issue here is the Data UDF is triggered twice: one time with the actual result, and one time with empty value of cell A1.
I tried setting calculation mode to manual, but it still gets invoked twice.
Is there any possible problem with this design or is there any way to set up the precedence in UDF so that Excel understands which UDF to trigger first?
I'm not sure how VBA code translate to c# for Excel, so I'll try to give a comprehensive explanation/example.
In VBA, there are two main ways to pass a reference for an excel cell (or Range) to a UDF.
Using a string parameter (i.e. Data(name as String))
Using a Range Object parameter (i.e. Data(name as Range) or more broadly Data(name as Object))
When the string parameter is used, the range's value is usually accessed in the code via Worksheet("Name").Range("String Param")).Value. When the object parameter is used, the code generally looks like RangeParam.Value.
There are also times when a range is hard-coded into or indirectly referenced by a UDF. I would avoid doing this; especially if that range contains a formula.
When Excel is doing calculations, it performs multiple steps.
Initiate calculations in each cell to determine the range parameters. (This is used to determine dependencies.)
Create the dependency tree with the proper order of calculations.
Do the finalized calculations in the determined order.
The important things to understand from this are:
If a range is referenced via a string parameter, Excel may not understand the dependency.
If a range is referenced in the calculation, but hardcoded in, indirectly referenced, or otherwise not passed in as a parameter, Excel will not understand the dependency.
If the UDF will get differing results depending on the number of times it's run, then there will be unexpected results (from Excel's multi-step dependency-determinations).
A few other notes:
If an error occurs in a UDF, how that's dealt with can vary a tad between whether the UDF being used in the worksheet or whether it's being called via other code.
I don't think you'll be able to prevent Excel from running the calculation twice, as that's part of how it's determining dependencies (unless I'm completely misunderstanding what you wrote). However, I would also expect that the calculation with the empty value of A1 would occur before the final calculation value with the actual result. If the second (final) calculation result is the one with the blank A1, then I'm not sure what to tell you, besides checking that all cells/ranges being referenced in a UDF are being passed into that UDF as parameter objects.
Make sure that cell A3 is empty before you insert the UDF into cell A1. The only way that the "Data" UDF gets called is if it already exists in the sheet you're adding it to. To clarify - If there is no formula in cell A3, then there's no way the "Data" UDF can get called. But changing the value in cell A1 by inserting the "Period" UDF will trigger the formula in cell A3 to recalculate, since one of the parameters being passed into it just got changed.
Another option would predicated on needing just the values and not the actual UDFs in the cells. In that case simply set the ".Value2" of the cells using the "Data" and "Period" functions, passing the "Period" value as a function into the "Data" function.
Range rngPeriod; //Set to cell "A1"
Range rngDate; //Set to cell "A3"
rngPeriod.Value2 = GetPeriod("KMP", "27-12-18");
rngData.Value2 =Data(GetPeriod("KMP", "27-12-18"),"KMP");
I am trying to create an excel file via c# in which the cells that contains the same data are merged. This is the easy part, the hard part is to make the excel display all the rows of the merged cells with the same value when filtering that value.
For example, for this data:
I expect this result after filtering the value "bla":
The result I would normally get after filtering merged cells is only the first row with this value (in this case, the row that contains the value "1").
I have found this solution which is extremely not elegant and not efficent:
Create two copies of the the data, in the first copy merge cells with the same values and in the second copy don't merge cells with the same value.
Use the format painter to copy the format of the merged version of the data onto the unmerged version of the data (apparently this way keeps the data of the cells but display them as merged).
delete the merged copy of the data.
I guess I can program this solution, but there must be a better way to solve this problem.
I have a very particular problem. I looked for similar problem to mine, test a lot of solution everyone proposed, but none of them is what I need.
My client need to export data sheet in excel format. Those data can be sorted, modified, rearranged, new values can be entered, some lines may disappear, some other can take their places, in short, anything can happen to those data. For example purpose, let's say that we export a list of item shown in a grocery list.
ItemID ItemName Price
Fr01 Apple 2.5
Fr02 Orange 4.0
Mt01 Beef 10.0
Mt02 Pork 8.33
Vg01 Carrot 1.25
My problem is that this data can be imported back in the software that originally created the excel to update (or add) these values in database base on the "ItemID". I already do validation if data is "correct" in value and type and interrelationality.
I tried to put a name to the range. The problem is when data is filter / sorted, the name don't follow the content, it stand still at the same position
original : (Range name is the name of the range, not an actual column)
ItemID ItemName Price || Range Name
Fr01 Apple 2.5 || data_fr01
Fr02 Orange 4.0 || data_fr02
Mt01 Beef 10.0 || data_mt01
Mt02 Pork 8.33 || data_tm02
Vg01 Carrot 1.25 || data_vg01
after sorting on ItemName:
ItemID ItemName Price || Range Name
Fr01 Apple 2.5 || data_fr01
Mt01 Beef 10.0 || data_fr02
Vg01 Carrot 1.25 || data_mt01
Mt02 Pork 8.33 || data_tm02
Fr02 Orange 4.0 || data_vg01
As you can see, all the info correctly follow, except the Range Name, so, when I try to import, I got a lot of data mismatch.
My other try was to make the NameRange an actual cell in excel. With this method, the cell follow, but can be changed, so I try to create a protected cell. Sadly, lines can't be inserted or deleted because of that. I found a workaround that consist in having names in a masked sheet, but once again, I need to synchronize sheets, which is not reliable for the same reasons mention previously.
Even worst, I must support both xls (97-2003) and xlsx.
So I'm looking for a stable workaround that will allow me to store somehow my "range name" data in the cell, making it invisible for the Excel User, but will follow the data so i can retrieve it at the right place when re-importing data.
Thanks in advance.
EDIT :
At finale, I must be able to write this property from C# application and then read back that same property with C#, and it must be compatible both excel file format, not viewable nor editable by excel user but stay with it's original value set, whatever happen to the data within the sheet except deletion (I don't mind if I just put it on the cell I wrote Apple in and not the entire range)
OK (I still think its better to add validation intelligence to the worksheet when you export but YMMV).
Try using the Range.ID string property - its not editable or visible from the Excel UI and it moves around with the cell. If the cell gets deleted it disappears. If a cell gets copied the ID property gets copied so there would be a duplicate.
It was introduced in Excel 2000 so probably won't work for Excel 97 but should be OK in all file formats for Excel 2000 to Excel 2013.
Here is some example VBA code:
Sub putids()
Dim j As Long
For j = 1 To 5
Range("a1").Offset(j - 1, 0).ID = CStr(j)
Next j
End Sub
Sub getids()
Dim j As Long
For j = 1 To 5
Debug.Print Range("a1").Offset(j - 1, 0).ID
Next j
End Sub
I think you should use some key column be it a unique name you've made up, a concatenation of the records making up your data row. Whatever. Make that as the left most column, hide it and lock it do users can't show that column or change it's contents.
Then in another worksheet, take those same values and starting in A2 paste them in.
Now in B2 enter this formula
=VLOOKUP(<this row's key value>,<Your data array in sheet1>,<column number>,FALSE)
Here is an example of how to so the fixed column/row settings
=VLOOKUP($A2,BigNamedRange,B$1,FALSE)
now Hide that sheet.
Now what you have in the first sheet is an area where your users can filter/sort/do whatever and in your second, controlled sheet, you have the data in the order you want to see it (which can be changed independently from the user's sheet).
Edit:
Click on 1: Allow Users TO Edit Ranges and set the range you want to let users edit.
Then, 2:, click Protect Sheet/Protect Workbook (which ever you need) to lock everything else.
Now your users can edit what you let them and not edit everything else
I don't see how named ranges help you.Have you thought of adding Validation code to the workbook using the before save event, so that the user cannot save data that is not valid? Or seeing how much you can do using Excel's data validation rules.Otherwise you have to read all the data and validate it later at DB update time (which is basically too late) Presumably the basic validation is that the iTemID is valid - your DB code won't care what order the data is in, and can skip empty rows etc.
Using a little of everyone suggestion and merge them.
Since any simple and normal solution isn't viable in our context and since the only possible property we can try to put something in (ID) isn't persistent and with the fact we need the client not to accidentally destroy the value considering the fact that anything may happen and will happen since there is no much restriction and the fact that we can't lock a part of the sheet without disabling line manipulation because of the side effect of the presence of a locked cell, the closest thing we were able to achieve was to insert our keys as a formatted string in column A with a weird looking formula allowing us to hide from display, then we hide the column, making it unreachable accidentally by the user.
=IF(FALSE,"our formatted string","")
Since this hidden column has data, it follows its line when sorted and trying to copy the entire line won't be possible with the fact that we select only from column B (which cause to try to insert 256 values in 255 cells) we can control a little the "false duplicate", even if not totally eliminated.
On the importer side, we just read back with a little trick comparing the formula with the value (since value is empty, only formula got our formatted data) and having a little regex to retrieve the meaning of our formatted string then doing all our validations before the actual database import.
For the rest, it will go to the training part of the user to not "delete" the data in column A, and not searching for it.
Thanks again to everyone.
I know how to make new columns, I know how to add a header to that column, but I am a little unsure about adding values programatically.
I am going to be looping through rows and then adding values to the new columns that I create based on some functions I perform on the Data Set. I thought a good way to start would be to just pick a row and loop through it and print out all the information in that row. If I could figure out how to do that, I could probably right all the code necessary to loop through appropriate rows and get the data I need. But I am a little confused about how to use this Range object...
Range rng = (Range)wkSheet.get_Range("A1", Type.Missing);
Lets say I wanted to print out all the Range Row information to a console? How would I loop through that Range and print out that information? Even change the information in the Range. I know how to change the value of a single row, the header, but changing multiple rows is alluding me.
object[,] values = (object[,])rng.Value;
Probably duplicate reading-from-excel
Someone's sent me a Word file full off address labels separated by tabs. See
I'm trying to figure out the best way to import the addresses into individual records. Probably just go with NameLine, Address1, Address2 for each one (3 fields that I can parse later).
What can I do easily with C# or VBA? Or UltraEdit?
I like Excel for things like this. Just copy the text from Word, paste it into Excel, and use the text import wizard with a tab delimiter, making sure to treat consecutive delimiters as one.
Excel can even parse it for you:
Cut and paste the columns so that it's just one long column with all the addresses. (Let's say column A)
Assuming each address record is 3 lines long, we want to get that into a format with three columns: Name, Address1, Address2.
In Cell B1, create formula =A1.
In Cell C1, create formula =A2.
In Cell D1, create formula =A3.
Select cells B1 through D3, or D4 if you have blank lines between each address record.
Copy.
Go to cell B4, or B5 if there's blank lines between each address record.
CTRL+END to select everything until the end of the data (basically, cells B5:DXX should be selected)
Paste.
Create a new record at the top with your desired fields names.
Example result:
Afterwards, you can copy the results into a new worksheet (sans formulae, so it'll just be static text), format the data however you want it, and sort the data to remove those pesky blank lines.
If all the tabs line up in Word, you should be able to Alt-Select to select individual columns, then cut & paste them into one sequential column so you just get one contiguous file of Address1,Address2,Address3,BlankLine, which should then be trivial to parse.