I created a custom Collection property for a XAML control:
class MyClass : DependencyObject
{
public ObservableCollection<object> MyCollection
{
get { return GetValue(MyCollectionProperty) as ObservableCollection<object>;}
set { SetValue(MyCollectionProperty, value); }
}
public static readonly DependecyProperty MyCollectionProperty =
DependencyProperty.Register(nameof(MyCollection), typeof(ObservableCollection<object>), new PropertyMetadata(new ObservableCollection<object>()));
}
but when I try to add elements to it in XAML:
<local:MyClass
*snip*>
<local:MyClass.MyCollection>
<x:Null/> // this causes a crash because it sets my collection to null
<Button/>
<x:Null/>
</local:MyClass.MyCollection>
</local:MyClass>
I get an XamlParseException - "...property has already been set ..." I think that what happens is the parser interprets the above code as a request to set my entire collection to null, then tries to set it to Button, then sets it to null. If Button is first then the Button and the nulls are added to my default list with no problem.
What is the correct syntax for setting the first element in a list to null in XAML? The Content Properties and Collection Syntax Combined section of XAML Syntax in Detail is the most useful reference I have found so far. My guess is that it will be some sort of Markup Extension, but everything I've tried gives the same sort of error.
One option would be to remove the setter from your MyCollection property - without an available setter, the XAML parser interprets your collection as an Implicit collection (one that can't be set, but can be added to.) This means that the parser won't interpret your initial x:Null as a null collection, and will instead add it to your existing list.
From XAML Syntax in Detail:
An implicit collection element creates a member in the logical tree representation, even though it does not appear in the markup as an element. Usually the constructor of the parent type performs the instantiation for the collection that is one of its properties, and the initially empty collection becomes part of the object tree.
Related
In the completed Avalonia tutorial Todo application --- where and how do TodoListView and AddItemView acquire their DataContexts to be equal to TodoListViewModel and AddItemViewModel respectively ???
I mean their parent control MainWindow's DataContext is a MainWindowViewModel instance (as assigned in App.xaml.cs file) --- while MainWindow's Content attribute is bound to MainWindowViewModel's Content property (which does get assigned instances of the viewmodels during execution). I just cannot trace the source wherefrom TodoListView and AddItemView acquire their DataContexts. Do they get it while:
Being created by the ViewLocator at runtime ? -- but that's not possible as the DataContext property of the newly instantiated View is still NULL just before the ViewLocator returns the View instance -- as shown by the output of following code in the completed application (the code in the if block is modified by me to produce required output):
public IControl Build(object data)
{
var name = data.GetType().FullName.Replace("ViewModel", "View");
var type = Type.GetType(name);
if (type != null)
{
var viewInstance = (Control)Activator.CreateInstance(type);
// the following always evaluates to true --- i.e. DataContext is always NULL before viewInstance is returned.
if(viewInstance.DataContext == null)
Console.WriteLine($"DataContext property of the newly created View instance of {name} in ViewLocator is NULL just before returning! ");
return viewInstance ;
}
else
{
return new TextBlock { Text = "Not Found: " + name };
}
}
OR they get their DataContext assigned by the parent Window ? --- but the parent window's own DataContext is MainWindowViewModel ----- how do we get to TodoListViewModel or AddItemViewModel from MainWindowViewModel ???
In short , I am unclear about where the Views generated at runtime via ViewLocator are getting their DataContext properties assigned.
Summarizing what I understood from the answer and some search and play:
If a ContentControl's (in this case Window's) Content property is a Control then the Control simply inherits the DataContext from the parent ContentControl. But if the ContentControl's Content property is a non-Control then the ContentPresenter of the ContentControl first finds a data template for the non-Control so that a child View can be generated and then sets its own DataContext to the non-Control. This newly assigned DataContext then gets inherited by the newly generated child View. Phewwwwww!
DataContext is inherited from ContentPresenter which is asking IDataTemplate.Build for a new view instance. When Content isn't a control, ContentPresenter sets its own DataContext to the value of Content which gets inherited by the child view.
ContentPresenter is used internally by the Window to display its Content property.
Same happens with ListBox items.
I have a Xamarin.Forms xaml page in which I am using a ListView to allow the user to pick a single item out of a list. I have bound the ListView's SelectedItem property to a property on my ViewModel and this works fine. As soon as the user changes the selected item the property in my viewmodel updates as well.
However, even though I initially set the property in my ViewModel to one of the values from the list, when the page loads the ListView's SelectedItem property is null, which in turn sets the ViewModel property to null as well.
What I need is the other direction, I want the ListView to initially select the item that i've set in the VM property.
I can hack together a solution by writing extra code in the code behind file to explicitly set the initial selected item, but this introduces additional properties and complexity and is quite ugly.
What is the correct way to set the initial selected item of a ListView who's selected item is bound to a viewmodel property?
-EDIT-
I was asked to provide the code that I'm using for my binding.
It's very simple, standard:
<ListView x:Name="myList" ItemsSource="{Binding Documents}" SelectedItem="{Binding SelectedDocument}">
the view model that is set as the binding context for the listview is instantiated before the page is created and looks like this:
public class DocumentSelectViewModel : ViewModelBase
{
private Document selectedDocument;
public List<Document> Documents
{
get { return CachedData.DocumentList; }
}
public Document SelectedDocument
{
get { return selectedDocument; }
set { SetProperty(ref selectedDocument, value);
}
public DocumentSelectViewModel()
{
SelectedDocuement = CachedData.DocumentList.FirstOrDefault();
}
}
SetProperty is a function which simply rasies the INotifyPropertyChanged event if the new value is different from the old one, classical binding code.
I am a little rusty on XAML but don't you need to make the binding two-way?
E.G.
{ Binding SelectedDocument, Mode=TwoWay }
As long as the SelectedDocument property change raises the INotifyPropertyChanged event then you should get the desired effect.
If you replace
public DocumentSelectViewModel()
{
SelectedDocument = CachedData.DocumentList.FirstOrDefault();
}
By
public DocumentSelectViewModel()
{
SelectedDocument = Documents.FirstOrDefault();
}
Does it work for you ?
I had a similar problem that has been resolved this way...
You can use ctor DocumentSelectViewModel for set initial value. Honestly I dont like to make some job in ctor block but Xamarin.... You dont need DocumentSelectViewModel method. It will work.
public DocumentSelectViewModel ()
{
SelectedDocument = Documents[0]; //or any your desired.
}
I had an idea to use custom attributes on the properties in a class for databinding purposes in a winforms interface. For example, setting and changing the backcolor, forecolor, and tooltip on a textbox with invalid data. I find that I can bind up the control properties of txtTest for backcolor, etc., to a custom attribute such as BackColorAttr decorating a property in the class such as Name, with no problem. The property value itself is bound to the Text of the textbox, two-way binding of that works just fine, and the initial backcolor, forecolor, etc., are set from the initial values of the custom attributes just the way I had hoped. I'm doing all this through a BindingHelper class that reduces all the coding to a couple of generic methods.
Where I'm stumped is manipulating the values of the custom attributes at a later time. Changing the backcolor to red, for example. Nothing I've tried seems to work. Has anybody tried something like this, or have some guidance as to how I might proceed?
I dont quite follow the first part or what binding has to do with colors or Attributes, but thats not how Attributes work. They are not Property wrappers and Properties, Methods and Types have no idea of the Attributes associated with them (and vice-versa). They are meta data compiled into the assembly. As such, you cant change the value in any meaningful way.
Test class and test Attribute:
Public Class BarState
Inherits Attribute
Public Property State As String
Public Sub New(t As String)
State = t
End Sub
End Class
Public Class Foo
<BarState("red")>
Public Property Name As String
End Class
Since State is a property, test if we can set it:
Dim f As New Foo
' get props for the Type
Dim pi As PropertyInfo = f.GetType.GetProperty("Name")
Dim attr = pi.GetCustomAttributes(GetType(BarState), False)
If attr.Length > 0 Then
' get prop info for the State property on the Attr Type
Dim pa As PropertyInfo = attr(0).GetType.GetProperty("State")
' change it
CType(attr(0), BarState).State = "GREEN"
' or
'pa.SetValue(attr(0), "GREEN", Nothing)
' print it (prints "GREEN" but it does not persist)
Console.WriteLine(CType(attr(0), BarState).State)
End If
'get the attr again as you might do next time thru
attr = pi.GetCustomAttributes(GetType(BarState), False)
' print the value (Print "red")
Console.WriteLine(CType(attr(0), BarState).State)
The first print will be "GREEN" but that is only for this instance - it does not persist. The next time you get it, it reverts to "red". Since an Attribute is a Type, we can try to Reflection to change the value using pa.SetValue(attr(0), "GREEN", Nothing) which is commented out. It still wont persist because "red" is compiled into the assembly which is what your starting point will always be.
It might seem like you could keep a Dictionary or collection of the attribute instances for all the properties on all the types. That could work except, they all look alike, so you would have to create a hash to track which Attribute instance goes with what Property on what Type.
And you'd have to keep that collection in sync with the underlying instance objects. The Attribute instance wont know the instance it came from is gone and so the state setting should revert, so your Attribute manager would need to handle that.
You might look into "weavers" which use attributes to tag things (like a value range) then rewrite the assembly to weave in range checks for the tagged properties. Sort of sounds like what you are after I dont know what else they might do along the lines of what you describe.
I have a base class ReportElement which has type property:
public abstract class ReportElement {
private ReportElementType type;
public ReportElementType getType() {
return type;
}
public void setType(ReportElementType type) {
this.type = type;
}
}
ReportElementType is just an enum with specified code and i18nKey properties for each element. I have a couple of subclasses of ReportElement, each of them introducing their own properties. One of them is Plot:
public class Plot extends ReportElement {
public Plot() {
setType(ReportElementType.PLOT);
}
private Collection<Parameter> parameters = new ArrayList<Parameter>();
public Collection<Parameter> getParameters() {
return parameters;
}
}
On some page I needed to display a collection of different ReportElement instances, so I just used struts2 select tag:
<s:select list="myElements" listKey="type.code" listValue="type.i18nKey" size="20"/>
This worked like a charm for every element except for Plot instaces. Instead of invoking getType().getCode() or getType().getI18nKey() plain toString() was invoked on every instance of Plot! After several hours of fun debugging I noticed that during tag evaluation Plot's getParameters() method is called! So it seems struts was trying to evaluate type.code and type.i18nKey using getParameters() method! Failing to do that it ignored the existence of the properties, that I have clearly specified for usage!
After renaming getParameters to a kind of odd name like getParamms the problem gone. Also the problem hasn't occured when using iterator tag together with property tag instead of select tag.
Does anyone have an idea WHY struts select tag uses parameters property of my bean, when I have clearly specified what property should be used? Is it some "cool" feature or a bug?
P.S. I use struts 2.2.3.1
The argument used in all the FreeMarker templates representing a tag's parameters is called parameters. By providing a parameters property that takes precedence, S2 was unable to get to the object on the stack containing the tag's parameters.
It's neither a cool feature nor a bug, it's just how the templates are implemented. Checking the template source may have saved the few hours of debugging.
Found corresponding issue in struts JIRA: https://issues.apache.org/jira/browse/WW-3268
2.3 is specified as fix version.
I have this problem at hand and wanted some inputs on best way to approach it -
In my application, i have different set of objects and each object has some properties associated with them.
For eg: objects like, say, shapes , which has some common properties like color and specific properties ( for eg: circle has radius and center has its specific property )
The user can change object properties through a property inspector.
Currently, the PI holds a object ID and uses that to talk to DOM for anything related to object it currently refers. like say, if it wants to change the property of object it will call DOM Api
ChangeObjectProperty(objectID , *);
(I hope using object ID to refer to objects inside the DOM is right way. (is there a better way to do this ?))
What should i pass as the second argument ?
Should it be a single opaque object ( say, IObjProps) where each objects provides its own structure ?
For example the circle will have following structure of its own -
class CircleProps extends CommonProps
{
public var radius:Number;
public var center:Point;
}
class CommonProps extends IObjProps
{
public function clone();
public var color:Number;
}
The DOM will pass on this structure to the object and object takes care of applying the change.
So ChangeObjectProperty(objectID , *); function will be implemented as -
function ChangeObjectProperty(objectID , props:IObjProps)
{
var object:Object = GetObjectFromID(objectID);
object.SetProperty(iObjProps)
}
The problem with the above approach is that - its kind of difficult to know what specific property changed since its a single structure -
The alternative is to have property dictionary - the client inserts only the properties which got changed into the dictionary.
I wanted to know what is design pattern followed for such use cases.
Adding more info - this is actionscript -