Binding IsEnabled to the parent ViewModel instead of the UserControl ViewModel
I developed a user control in SilverLight that contains several child controls. Textboxes
, ComboB开发者_JAVA技巧oxes
and so on.
The problem is, when I include that UserControl
into a parent view and set the complete control to IsEnabled=False
, the child controls in that specific UserControl
are still enabled.
After all I found the problem.
Adding something like that, implies that the IsEnabled
Binding is located in the UserControl
binding, not as expected from myself in the DataContext
of the parent.
<localControls:TeamEmployeeSelector Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
IsEnabled="{Binding CanModify}" DataContext="{Binding Confidentiality}"/>
QUESTION:
But there's still the question how I can bind theIsEnabled
to the ViewModel of the Parent? Because it's not very elegant to copy the CanModify
Property to the ViewModel of the Child Control.Instead of modifying a binding in some way (for example you can make it dependent on other control name as it is proposed in other answer) I would move separate the control which will be disabled and control where DataContext
will be changed. For example:
<ContentControl IsEnabled="{Binding CanModify}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
<localControls:TeamEmployeeSelector DataContext="{Binding Confidentiality}"/>
</ContentControl>
Here is how I would do this.
Your TeamEmployeeSelector
UserControl
will contain a single root level element which by default is a Grid
and is given the name "LayoutRoot".
Now you can bind the IsEnabled
property of all the child elements to the UserControl
like this:-
<TextBox IsEnabled="{Binding Parent.IsEnabled, ElementName=LayoutRoot}" ... />
By using element-to-element binding you do not need to copy the CanModify
property in to child view models.
Some might suggest that you simply add an x:Name
to your UserControl element and then bind directly to it rather than going via the Parent
property of the root element as I do above. That'll work ok in Silverlight 4 but not in 3 or WP7. Personally I prefer the above.
This is a scoping issue. Generally, when creating a UserControl
, you want to set itself as the DataContext
for its sub-elements. This is most easily accomplished in the constructor:
UserControlExample() {
InitializeComponent();
RootElement.DataContext = this;
}
Where RootElement
is the name you give to this first child (usually a Grid or panel) of your UserControl
.
From here you can set natural bindings for your sub-elements like so:
<TextBox x:Name="MainTextBox" IsEnabled={Binding IsEnabled} />
This works, since TextBox
inherits the DataContext
of the parent layout panel.
Finally, if you want to have your UserControl
's IsEnabled
property to be related to its parent, this is best done at the point of declaration:
<Grid>
<UserControlExample IsEnabled={Binding CanModify} />
</Grid>
This way you keep your concerns separate. The sub-controls don't care what the UserControl
is reflecting. They just need to know how to enable/disable when the control's IsEnabled
property flips.
sub-controls IsEnabled bound to --> (UserControlExample is DataContext)
UserControlExample.IsEnabled bound to --> (VM is DataContext)
VM.CanModify
I don't know if it's possible in Silverlight, but in WPF I would use RelativeSource.
Have a look here.
Hope this help !
<localControls:TeamEmployeeSelector Grid.Row="1" Grid.Column="0"
Grid.ColumnSpan="2" IsEnabled="{Binding ElementName=SomeElementName_With_Parent_ViewModel, Path=DataContext.CanModify}" DataContext="{Binding Confidentiality}"/>
精彩评论