EPiServer: Can I set a dynamic property from code-behind? - asp.net

I tried to set it as a normal page-property, but no luck.
Guess I could use the DynamicProperty class but I really want to avoid this because of the no-cache issue.
Suggestions anyone?

AFAIK the only way to do this is with the DynamicProperty class. If you look at the documentation on the indexer property on the PageData object it says:
Note! Using this indexer will use the Pre and Post handlers for property lookup. I e return values are not guaranteed to belong to the page, but may be dynamic properties, "fetch-data-from"-data etc. To get data guaranteed to belong to this page, use the GetValueand SetValue methods.
Also note that setting values with this indexer will only set values that acually belong to the page, i e you may get a valid value by reading from the indexer, but trying to set a new value for the same index may yield an exception since the value does not exist in the page.
You will need to use the DynamicProperty class:
DynamicProperty myDynProp = DynamicProperty.Load(CurrentPage.PageLink, "PropertyName");
myDynProp.PropertyValue.Value = "new value";
myDynProp.Save();
Alternatively, you could circumvent the Dynamic Property using an idea Joel discusses here

Related

Why can you set a lit public property 'attribute' option to false?

From the Lit documentation: "The component shouldn't change its own public properties, except in response to user input."
Also from the documentation: "Internal reactive state works just like public reactive properties, except that there is no attribute associated with the property."
However, when you declare a property, there is an option of setting attribute to false, which prevents an attribute from being associated with the property.
#property({attribute: false})
data = {};
What would be the purpose of doing this? Wouldn't the property just act like internal state at that point?
For reference, Lit already has several ways of declaring internal state variables, either with the #state decorator or setting the state option to true, so I'm just not sure why they allow this too.
I think the main use case for this is for when you have to pass big complex data to the component but want it to be set directly as a property and still get lit to rerender stuff for you.
I think this is easier to visualize with an example, let's say you're making a component which will render a list out of an array passed as a property.
If the array was set as an attribute, it would look something like this:
<list-renderer items='[{id: "1", name: "John Doe"}, {id: "2", name: "Alice Williams"}]'></list-renderer>
Now, this example only has two items, but it could be something way bigger, and that attribute will eventually need to be serialized into an array using JSON.parse() by lit. So, you're just doing an extra step, especially if you already had the array as a JS object rather than JSON data.
So, for this kind of cases it's easier to just force users to set items as a JS property directly.
This will also apply for when you need to pass complex configuration setting objects or functions to the component.
Then again, for most of the components you'll be making, you will probably stick with either having the attribute or making it a fully internal state property.
This way you are really free to use any combination.
A property which acts also as state and attribute
A property which acts also as state but not as an attribute
A state, which is not a property
A property, which is an attribute
A property which is not an attribute
see also https://javascript.info/dom-attributes-and-properties for the difference between properties and attributes.

Multiple "default" properties/methods in a VB6 class?

I am trying to make a replacement VB6 class for the Scripting.Dictionary class from SCRRUN.DLL. Scripting.Dictionary has (among other things) a "Keys" method that returns an array of keys, and a read/write "Item" property that returns the item associated with a key. I am confused about this, because both of them seem to be defaults for the class. That is:
For Each X In MyDict
Is equivalent to:
For Each X In MyDict.Keys
Which to me implies that "Keys" is the default operation for the class, but:
MyDict("MyKey") = "MyValue"
MsgBox MyDict("MyKey")
Is equivalent to:
MyDict.Item("MyKey") = "MyValue"
MsgBox MyDict.Item("MyKey")
Which to me implies that "Item" is the default operation for the class.
I've never before created a VB6 class that had a default operation, so upon realizing this, I thought perhaps I could define multiple default operations as long as they all have different signatures, which they do: Keys is nullary, the Item getter takes a Variant, and the Item setter takes two Variants. But this doesn't seem to be allowed: When I use "Tools/Procedure Attributes" to set the Keys function to be the default, and then I use it to set the Item property to be the default, the IDE complains that a default has already been set.
So I think I'm misunderstanding something fundamental here. What is going on in the Scripting.Dictionary object that makes it able to act as if "Keys" is the default in some contexts, but as if "Item" is the default in others? And whatever it is, can I accomplish the same thing in VB6?
OK, answering my own question: I haven't tried this yet, but I gather that "Item" should be made the default, and that I should add an entirely new function called "NewEnum" that looks something like the following (slightly modified from an example in Francesco Balena's "Programming Microsoft Visual Basic 6.0" book):
Public Function NewEnum() As IUnknown
Set NewEnum = m_Keys.[_NewEnum]
End Function
(where "m_Keys" is a Collection containing the keys), and then use Tools/Procedure Attributes to hide NewEnum and to set its ProcID to -4.
What you are observing is the difference between the default member and a collection enumerator. A COM object (including VB6 classes) can have both.
You can identify the default property of a class by looking in the Object Browser for the tiny blue globe or the words "default member of" in the description (see Contents of the Object Browser). The Object Browser will not identify an enumerator method, but if you look at the class's interface definition using OLE View or TypeLib Browser (free but registration required) it's DispId will be 0xfffffffc or -4.
In your own class, you can mark the default property by setting the Procedure ID to "(default)" in the Procedure Attributes dialog (see Making a Property or Method the Default). You already listed the steps for setting up the collection enumerator in your own answer, but you can find this listed as well in the Programmer's Guide topic Creating Your Own Collection Class: The House of Bricks.
Scripting.Dictionary has a dirty secret:
It does not handle enumeration at all, it returns big ugly Variant arrays and your For Each loops iterate over those.
This is one of the reasons why a Dictionary can actually be far less efficient than a standard VB6 Collection.

ASP.NET: Can you use server tags to embed C# or VB.NET expressions into a Javascript function?

I have an enum called SiteTypes that contains several values that are all bound to a dropdown list. On the client side, I need to check this dropdown to see if the selected value is one of those enum values. I don't want to hardcode the value of the enum in the script in case it needs to change, so I want to use a server tag to get it directly from the enum itself. Conecptually, I would like to do this:
function SiteIdChanged() {
var x = "<%=SiteTypes.Employee %>";
}
The way I am doing it now is created a protected property in the codebehind that returns that specific enum value and am doing this:
function SiteIdChanged() {
var x = "<%=EmployeeSiteTypeValue %>";
}
I don't like that, though, because I have to create a special property on every page that I need to do such a check.
Is there a way to do what I want here?
Are you getting a "xxx is inaccessible due to its protection level" error when you compile or run the page? enums are public by default, classes are not. My guess is that you've defined your enum inside your page's class and you aren't explicitly marking it with the 'public' access modifier. Explicitly mark it as public or move it outside of the class and see what happens. If you're planning on using it on lots of pages you should stick the enum definition in in a file in the App_Code folder of your project.
If you don't like your current implementation I would consider using a PageMethod to compare the dropdown selection to the enum value. This approach will probably be cleaner, as you can do most of the logic server-side.
Here's a tutorial on PageMethods:
http://blogs.microsoft.co.il/blogs/gilf/archive/2008/10/04/asp-net-ajax-pagemethods.aspx
As long as your enum is marked public, you can just go with your first option. There's no need to put a property on every single page you want to retrieve the value from.
That approach is really the simplest solution for writing out server side values in your JavaScript.
You can use the Enum.IsDefined Method this well tell you if the selected value from the dropdown is actually part of your enum.
Enum.IsDefined(typeof(MyEnum), myValue)
http://msdn.microsoft.com/en-us/library/system.enum.isdefined.aspx

ASP.Net: Is it possible to skip databinding of an element if an error occurs?

I use a lot of repeaters for different elements of our sites, and I've always wondered if there was a way to have the repeater skip an element if an exception occurs instead of having the whole page crash?
In particular, I've inherited a system from another developer that using a similar design, however he didn't include any kind of validation for his business objects, and it a single property is missing, the whole thing goes up in smoke.
Any suggestions?
Thanks in advance!
The simplest suggestion I can offer is the check the validity of the data before it's passed to the repeater. I don't believe there's any way to get the stock repeater to skip a data element on error.
The other approach is to build your own repeater, inheriting from the base Repeater, to add that functionality but I've no sample code to offer. Perhaps someone else may be able to help there.
The way I see it, you have at least three options.
You could create a custom repeater control that inherits System.Web.UI.WebControls.Repeater and override the databinding behaviour to be more try-catchy (probably fail silently on databinding errors). You couldd then easily replace all instances of the standard Repeater with this new one.
You could filter your datasources before databinding to remove items you know are going to cause problems beforehand. This option may be quite laborious and something of an iterative process.
You could try adding default values to the business objects, so that the properties you're binding to return a default instance rather than null (not nice either).
That's my thoughts anyway.
One question - you say "when a property is missing". Do you mean he's using a style of databinding syntax that offers no compile-time checking and is referencing properties that don't exist, or is referecing properties that are null?
Edit
OK, so you're referencing properties that are null. If you have access to the code for the business objects you could modify them so they return a new, non-null instance (this is the third option I gave).
You don't say if you're using .net 3.5, but I'll assume you are. You could add a new property "IsValidForDataBinding" on to each of your business objects. In the getter logic you could check each of the necessary properties and sub-objects to check for validity, non-nullness etc and return a bool. When you come to bind your repeater, write a simple linq statement that filters-out the invalid items (i.e. where IsValidForDataBinding = false). Having said that, I still think that writing a derived repeater control could be your easiest option.
Have you tried using string.isnullorempty("the string") to check for a value before referencing the property?
Here's a reference: MSDN

Can you prevent LinqDataSource from setting a property?

I've got a Linq 2 SQL object I'm trying to update. Two of the properties on this object are related to each other, and setting one sets the other.
So if I do:
Foo.Code = BEER;
The Foo.CodeID property will automatically be set to 5 (or whatever.)
The problem is that LinqDataSource sets Foo.Code, then immediately sets Foo.CodeID... which is not bound to anything since we want the users to set just Code. This immediately sets them both back to null.
I know I can use Parameters to default values, but is there any way to just tell LinqDataSource to not even set a property?
EDIT: Worked around issue by creating a hidden field, and assigning the correct value to that in the formview's ItemUpdating event. Would still like to avoid doing the same lookup four times though...
Would it be an option to make the Code property private (select the Code property in the dbml and set the access property in the Properties window) and create a new public property over which you have more control?
I personally have have written a generator that generates the necessary files for me (like sqlmetal), giving me full control over the code. Perhaps this is an option for you as well, if you do not like the generated dbml.

Resources