silverlight - binding to two objects - data-binding

I want to create a user control, which can be bound to some data given from outside the control (requirement A), and some XAML properties must be bound to properties of the control itself (requirement B).
Let's say that I have a data class named StudentData and a control named StudentControl. I'm using this control inside a DataGrid. I put the StudentControl in the grid with a DataGridTemplateColumn. I somehow bind the StudentData in the current cell to the control. This is requirement A. This StudentControl wants to specify if some of the controls inside it are editable or not. The best way to do this is exposing a property, like StudentControl.AreSomeControlsEditable. Then I can bind the IsEnabled property of those controls to this property. This is requirement B.
Here's my first idea. I bind the current StudentData to a DP of StudentControl, then, inside the StudentControl, I change the data context to the control itself:
<UserControl DataContext="{Binding RelativeSource={RelativeSource Self}}">
<TextBox
Content="{Binding Path=ExposedStudentData.Field1}" *reqA*
IsEnabled="{Binding Path=OtherProperty1}" /> *reqB*
</UserControl>
This way, I figured, the StudentControl gets the StudentData from outside, exposes this same StudentData and the other new properties (so the data and other properties are in one place now, not two), and then I can bind to these exposed properties in XAML (reqA+reqB are fulfilled at the same time). Except this doesn't work because of this bug. Basically, if I set the DataContext of the control to itself, then it gets set before the outer binding is applied. So if my binding path inside the cell is X, and then the data context changes, the binding engine will look for X in the new, self data context, and not the outer, grid data context.
Here's my second idea. I bind the current StudentData to the DataContext or a DP of the StudentControl. Then, to access other exposed properties of the StudentControl, I give a name to the UserControl and use ElementName binding:
<UserControl x:Name="self">
<TextBox
Content="{Binding Path=Field1}" *reqA*
IsEnabled="{Binding ElementName=self, Path=OtherProperty1" /> *reqB*
</UserControl>
This way, I figured, the current data context is the StudentData, and it's not changed, and I can bind to that with a simple path (reqA), and I can bind to the other exposed properties with the ElementName stuff (reqB). It works in basic scenarios, but not in a DataGrid, because of this bug. I'm guessing the problem arises when there are multiple controls with the same name in the visual tree.
I'm really starting to hate Silverlight, I started using it a month ago, and I already reported 9 bugs. Whenever I try to achive something other than a simple hello world application or something that Microsoft and everyone else seems to be using Silverlight for, I encounter a new bug. So what now, how would you bind to a data class given from outside the control and some other properties exposed by the control at the same time? Without, of course, setting up the bindings from code (which I'm doing now, but it's a nightmare with ListBoxes and DataTemplates) or not using binding at all.

I think your problem is with the DataContext and how it is inherited, as well as namescopes.
For the first, you should know that if a control doesn't specify its own DataContext, it will inherit that of its parent, and for ItemsControl derived controls, each Item will have its DataContext set to one of the data items in the ItemsSource collection.
For your second problem, if you're inside a DataTemplate, you're in a different namescope than outside of it. You can't access controls "by name" outside of a DataTemplate. What you can do here (for Silverlight 4 and below) is to traverse the Visual Tree yourself and look for the control you want. This, however, is going to become much easier and less painful with some new features in SL5, specifically the "FindAncestor" feature (which already exist in WPF).
Here's an article on MSDN about Namescopes in Silverlight. And here's another one about DataBinding which mentions how DataContext is inherited.
To achieve what you're looking for, I think this blog post should help you. It shows you how to implement "RelativeSource Binding with FindAncestor"-like behavior in Silverlight.
Hope this helps :)

On another forum, they told me to use MVVM. As it turns out, it can make my first idea a little better. Instead of binding my StudentControl to a StudentData, and then exposing this data and other properties, I should create a viewmodel, let's say StudentControlData, which contains a StudentData and additional properties required by the control. If I bind my control to this, then in the inherited data context of the control, I have access to all properties that I need. Now the only problem left is that inside a ListBox in my StudentControl, I lose this data context.

Related

mvvm-light: Normal Property or DependencyProperty

In mvvm-light, it comes with two property-creation snippets: mvvminpc to create a 'normal' property; and mvvmpropa to create an attached property (aka dependency property). I just want to know if there is any guidance on what to take into consideration when choosing which one to use?
I've been also searching for a while on these property topics for MVVM light. Below is my understanding of the property snippets provided in MVVM light. There aren't really any cases where you would use one over the other because they are for different purposes.
Bindable Property - Bindable properties are created in your ViewModels to expose data which your view will display.
Examples include: Displaying a collection of Employees, or the selected employee information.
Dependency Property - View specific when it comes to the code snippet. These properties can be set to a constant value or use data binding for changes depending on the viewmodel data.
Examples include: A textblock control's "Text" property is a dependency property. The "Height" and "Width" properties are also dependency properties.
Attach Property - Also used more specifically for user controls. This property is added to a parent control. Child controls use these properties to behave a certain way within the parent control.
Example includes: a Dockpanel has a "Dock" (Attached Property Name) that isn't used by the Dockpanel itself. It is used by the children contained inside of it, the children will now be able to set the property: DockPanel.Dock="Top".
<DockPanel>
<TextBlock Text="{Binding EmployeeName}" DockPanel.Dock="Top" />
<Button Content="Click Here" DockPanel.Dock="Bottom" />
</DockPanel>
In the example code above:
The Bindable Property is the EmployeeName, which would be a public property in the viewmodel code.
The Dependency Property is the Text="" property of the textblock and the Content="" property of the button.
The Attach Property is the DockPanel.Dock property used in the Textblock and button, but is actually exposed by the Dockpanel itself. Notice that the Dockpanel doesn't contain any of the .Dock code, only the children do.
Dependency properties are recommended when you create UI components (controls, etc.): they have better time performances for binding.
Normal properties are used if you have business object or if you dont have/create UI controls.

Is there a reliable way to "refresh" a component?

By "refresh" I am completely disposing it and then introducing it again in the application (without closing the application itself - that is). Other than than I think the question is self-explanatory.
Example:
Say I have a component named myComponent. I add that component to the application using MXMl in the standard way <components:myComponent id="myID" />. Say that when a user clicks a button (the button may be in another state), the component with id myID should be garbage-collected and a new instance of it added to the application.
How do I go about doing that? If there are multiple solutions which one is the optimal performance-wise?
I am new to Flash and Flex so excuse me if any incorrect terminology were used.
Remove all the event listeners from the old component; whatever they are using the removeEventListener method:
myButton.removeEventListener(someEvent, someEventHandlerMethod);
Then all variables that refer to the component should be set to null. If created in an MXML file, like this:
<s:Button id="myButton" />
Then all you have to do is set that value to null:
myButton = null;
Once there are no references to the component, it can safely become eligible for garbage collection.
If you want to re-created, then just re-created it. You'll have to re-create it in ActionScript, but the code isn't hard. Conceptually something like this:
myButton = new myButton();
myButton.properties = propertyValues;
myButton.addEventListener(someEvent, someEventHandlerMethod);
parentContainer.addChildAt(myButton, whateverPositionYouWantToADdTheComponentAt);
I'm not sure I see the benefit of doing this. I suspect it'll be much more efficient to tweak the existing button instance in the way you need to as opposed to destroying it and trying to replace it with the exact same thing.

Accessing properties of AdvancedDataGrid runtime vs. design time

I am new to Flex and trying to modify some existing code. I am trying to It uses and AdvancedDataGrid. In the click event, the ListEvent is passed in, and the code is able to access properties such as event.itemRenderer.data.feature.
I would like to check whether the user has clicked on a parent (group) record or the child record; at runtime, I can see that the property I want to access is event.itemRenderer.listData.hasChildren. However, the listData property of itemRenderer does not show up in intellisense, and when I try to access that at design time, the project will not build because of the error "Access of possibly undefined property listData". But the property .data.feature doesn't show up in intellisense at design time either, and that builds and runs just fine.
What do I need to do to access event.itemRenderer.listData without throwing errors when I build the project? Do I need to capture a different event, or cast the event object or one of its properties into another object that will have the properties I need at runtime (I've investigated these options but cannot find info on how to do that).
Many thanks for any insight.
You probably have to perform a cast using IDropInListItemRenderer and AdvancedDataGridListData. Something like this:
((event.itemRenderer as IDropInListItemRenderer).listData as AdvancedDataGridListData).hasChildren

MVVM - what should contain what... what should create what

I'm having a right barney getting my head around how everything fits together using the MVVM pattern. It all seems quite simple in practice but trying to implement it I seem to be breaking various other rules that I try to code by.
Just as a side note, I'm trying to implement the pattern using Flex, not Silverlight or WPF, so if anyone can come with good reasons why this shouldn't be done, then I'd like to hear them.
I have a problem where I have several views. Sometimes I have to display two views on the page at the same time; sometimes I switch back to a single view. In my normal Flex brain I would have a main view with a code-behind which contained all my other views (equally with code-behinds). That main view would then do the switching of the other individual views.
When I try to implement this in MVVM I'm trying to stick to the principles of MVVM by using binding which decouples my Views from the ViewModels. Let's say I create a ViewModel for application-wide state and my ApplicationView binds to that data and does all the switching of the sub views.
Now, where should I create my view models for my subviews? I've tried inside the ApplicationView -- that didn't seem right. And then I've tried outside of the application view and passing and instance of it into the ApplicationView and then my sub models a bind to it. Am I missing something? None of these methods seem to fit the whole point of trying to decouple this.
Any good books or links that explain this problem would be much appreciated.
Cheers,
James
The approach you are referring to is ViewModel composition. Its where you have multiple complex view parts that need to bind to their own ViewModel entity. The approach entails constructing a root ViewModel with properties for each child ViewModel. Then the root View is bound to the root View Model and each View (whether displayed or collapsed) is bound to the corresponding property on the root ViewModel.
The ViewModel would look like this:
public class RootViewModel
{
ChildViewModelA ChildA { get; set; }
ChildViewModelB ChildB { get; set; }
}
The View would look like this:
<Grid>
<ChildViewA DataContext="{Binding ChildA}" />
<ChildViewB DataContext="{Binding ChildB}" />
</Grid>
You could also implement this in away to allow yourself to select an active workspace.
The ViewModel would look like this:
public class RootViewModel
{
public List<ViewModel> ChildWorkspaces { get; set; }
public ViewModel ActiveWorkspace { get; set; }
public RootViewModel()
{
ChildWorkspaces.Add(ChildViewModelA);
ChildWorkspaces.Add(ChildViewModelB);
}
}
The View would look like this:
<Grid>
<Grid.Resources>
<DataTemplate DataType="ChildViewModelA">
<ChildViewA />
</DataTemplate>
<DataTemplate DataType="ChildViewModelB">
<ChildViewB />
</DataTemplate>
</Grid.Resources>
<ContentControl Content="{Binding ActiveWorkspace}" />
</Grid>
This will result in the appropriate visual representation being selected implicity based on the type of the actual object stored in ActiveWorkspace.
Pardon my response was in WPF. I tried my hardest to not get caught up in the syntax of it all :-)
As you can see the plurality of "ViewModel" can be ambiguous. Often times we find the need to construct multiple sub-entities to structure the ViewModel appropriately. But all ViewModel entities would be somewhere within the root View Model object.
When implementing MVVM in WPF, I prefer to infer what visual element to apply data context implicitly (as illustrated in the later half of this response). In more complex scenarios I prefer to use a DataTemplateSelector to conduct that decisioning. But in super simple cases you can explicitly apply DataContext either imperatively in C#/ActionScript or declaratively through bindings.
Hope this helps!
I've seen variants of the MVVM approach used on a couple different Flex projects, but I haven't seen an approach that feels perfectly right to me. That said, I think using Presentation Models makes testing in Flex a lot easier, so I'm pretty sure that there will start to be more applications designed around this pattern.
The easiest approach I've seen to implementing MVVM in Flex is to place the individual ViewModels within the application Model / ModelLoactor. The ModelLoactor contains any global data and also serves as an accessor to all ViewModels. ApplicationViews can then bind to their particular ViewModel through the ModelLocator, while ViewModels can be updated both through Commands and through bindings to their parent ModelLocator. One benefit of this approach is that all of the data logic is localized; of course, this could also be seen as a drawback, with the central ModelLocator being a touch brittle due to its hard coded references to all ViewModels.
I've seen cleaner approaches work by using the Mate framework. Mate allows for a much more decentralized injection of ViewModels into the appropriate ApplicationViews. (I suppose this could also be accomplished with Swiz, I'm just not as familiar with that framework). With Mate, each ApplicationView has its ViewModel injected via a Map. What's cool with this approach is how ViewModels can be updated using an EventMap (the Mate version of a FrontController). Essentially, your ApplicationViews will dispatch events that are handled by one or more EventMaps, and these Maps can then make changes to one or more of the ViewModels. This approach allows for a user gesture or event from one ApplicationView to change the state of several ViewModels at once. In addition, because this logic is extracted into Mate's EventMaps, it's very easy to change how events are handled or which ViewModels are changed. Of course, the major drawback of this approach is that you're committing to using Mate as a framework, which may not be an option depending on the requirements of the project.
I hope that helps!
I wanted to share a comparison I wrote up of MVVM (Silverlight) vs PresentionModel (Flex). It shows how the two implementations of the same pattern differ/compare:
http://houseofbilz.com/archives/2010/12/29/cross-training-in-silverlight-flexmvvm-vs-presentation-model/

Actionscript 3 Bind variables

I am trying to set one bindable variable to be bound to another. Essentially I want to create an alias. I would give up, but this seems like something that would be good to know.
essentially, I want changes in model.configView to be reflected in view, so that things bound to view.... behave the same as things bound to model.configView... in this example [Bindable]
var view = model.configView;
...
<mx:Label text="{view.lblThisLabel.name}" />
at the moment it does not, and I am getting errors that say "unable to bind to property 'lblThisLabel' on class 'Object' (class is not an IEventDispatcher)"
Not quite enough code here to really say what's going on, however you have made view bindable and that does not automatically mean that all of view's children are bindable. You'll have to go into view and make lblThisLabel bindable too.
Also it is hard for the rest of us to know how it works in your head. Perhaps you should describe that too.
Moreover, I think that even if, with your actual code, view changes should be detected, view won't be updated if assigned model.configView property is not bindable as well...

Resources