I wrote a custom Silverlight 3 control that uses a class as its data context (MVVM pattern). I want to place this control on another control (form) through XAML. The child control exposes a Dependency Property that when set through XAML, will make it show detailed info.
So an example is that the child control shows order details data, and I want to place it on a form that show user orders. When you select an order, the selected item value on the parent control (orders list), is data bound to the child control, to show details.
The problem is that the child control’s dependency property's OnChanged handler never gets called. If I do not set a data context on the child (so it uses the parent's data context) all works fine, but when I set a different data context, it breaks down.
Ideally, your ViewModel would be for the outer UserControl and a property on the ViewModel will be the DataContext of the Inner/Child userControl
Its true that when the Parent control's DataContext is set, it is propogated down to all its child controls. But the child control has an option of overriding this behavior by setting its own DataContext (which you seem to be doing in your example). Hence by the rule of preferences, the child control's DataContext is given more preference and thus it overrides the parent's one. Also since the child's DataContext never changes after it's initially set, the DP never gets invoked.
So I thought about this some more, and I understand what is happening, but I think its very confusing, and is not done right. If I am doing data binding on a control in the main page, it should use the context of that page to do the binding. And binding I do inside the control should use the control's context.
The way it works now uses the control's context no matter where I put the binding expression (unless I am doing E2E binding, then its using the main page's context). That is silly to me. But at least I understand it now.
I solved the problem using Element to Element binding, and got it to work. I hope the SL team would change this behavior.
Related
I have buttons on my Silverlight page where the opacity is bound to one of two properties on my ViewModel. I'm using the button command that changes the properties, in theory to affect all buttons bound to that property, but the only control that gets affected is the button that initiates the command (any one of them).
Any ideas on why the additional bindings don't work?
The whole thing is actually a little more complex where the buttons are on a Control with the bindings as DependencyProperties mapping back to the VM, and the bound properties are going through a ValueConverter.
It sounds like you need to raise the INotifyPropertyChanged.PropertyChanged event for the properties that are changing. This will let the controls that are bound to them know that there is a change and that they need to come back and get the latest value.
I found the problem. The opacity binding wasn't working, but what was happening was the button was disabling itself based on the predicate I had set in the RelayCommand. It looked like the effect I wanted, but only affected the button being pressed because each button was bound to a seperate ICommand.
I changed it to remove change the binding from the OpacityProperty to the IsEnabledProperty, and removed the predicate from the RelayCommand declaration. It all works now as intended.
I don't know why the button would change to a disabled view when it checks the predicate (and finds it false), but never change back if the condition changes. Odd.
I have a window called MAINWINDOW that has a toolbar and a frame. Inside the frame is shown a Page called HOMEPAGE. This page has a treeview where menu options are shown. When the user clicks a node, the corresponding form (a Page) is shown inside a border in HOMEPAGE, using the Border.Content property. I have a button in the toolbar to search for customers and I need to bind this button's command property to a command which is defined inside the Customers page's viewmodel. This page is a child of the HOMEPAGE which in turn is a child of MAINWINDOW. Can you suggest a way to do this, that is to access a command defined in a child's child object?
Thank you.
That goes against the principles of MVVM.
ViewModels (and their corresponding Commands) are 1:1 to Views. Each ViewModel serves one View, and one View ONLY. It helps to think of the ViewModel as the codeBehind of the View, only that it can never access the View directly (thus it's completely decoupled from it).
Violating this principle (V to VM == 1:1), creates dependencies between ViewModels or between Views, which is a bad thing. It makes your application harder to maintain since each "module" is dependent on the implementation of other "modules".
What you should do is expose another Command on the ViewModel that serves the relevant View. That Command in turn could trigger what ever you want.
Would it be possible to bind to Validation.HasErrors on any child control of a panel, without explicitly binding to every named control? Specifically i want to fire a trigger on a general style of a panel if any child control is in error state.
Thanks.
I would use an attached behavior that uses the LogicalTreeHelper (or VisualTreeHelper as a backup) to subscribe to the dependency property changed event of Validation.HasErrors for each child element via DependencyPropertyDescriptor. From there you would just update your own attached property (say, CompositeValidation.HasErrors) and bind to that.
I have a custom text box control which raises a routed event when its TEXT property changes. This text property is data bound to a property on our view-model object.
When I place this control on a TabControl page or Expander control, it appears as if data binding only occurs when the control becomes visible for the first time, therefore I never receive any of the routed events until I swap to the tab the control is on or expand the expander.
Is there any way I can force data binding to occur before the control is shown?
Sounds like you relying on the data binding to genreate the routed event is the wrong approach. Instead you need to have your Model or ViewModel generate an event when the text is modified and then you watch this event from an appropriate place in your View.
Not very likely. WPF is a fairly efficient framework and won't do any work that it doesn't absolutely have to. This includes scenarios like data binding. Why bother exercising a collection for a control that might not ever be shown?
I have a small usercontrol that basically increments or decrements a value by one. The user control has two buttons(one to add and the other to subtract) and a textBlock that is used to display the value.
I am going to have multiple instance of this usercontrol in another usercontrol so I can manipulate values of a dataclass that has an INotifyPropertyChanged interface. My question is how can I databind the textBlock of the value changing usercontrol to the usercontrol I instansiated it in?
First, I want to state that Silverlight 2 does not support element to element binding. That feature is added in Silverlight 3 (out in Beta now). Having said that, I don't think you want to bind controls together anyway. It sounds like you're trying to build a NumericUpDown control and you probably have some class in code behind that's actually doing the incrementing and decrementing.
If that's the case, you can simply subscribe to the click handlers and call a method on your model like Increment or Decrement. Your model can expose a property for the current value and that property is what is bound to your text box.
Now if you're actually trying to build a NumericUpDown control, you might want to check out the Silverlight Toolkit. The toolkit already includes this control and it also supports data binding.
Check out the NumericUpDown Control here and download the toolkit here.
Finally, binding from a child control to a parent control really isn't any different. The parent UserControl has a DataContext and all child controls inherit that. Each individual child control can also have its DataContext set. Binding expressions are always relative to the DataContext and the DataContext can be set in code. In your case, probably to a model of some sort.
I hope that helps.