WPF ReadOnly Dependency Properties using MVVM
I've recently overridden the DevXpress WPF grid to give myself a SelectedObject property that I can access from my loosely bound ViewModel.
I've made a SelectedObject dependency property and have it bound OneWayToSource in my XAML.
Everthing works fine, but if I try to make it ReadOnly (for completeness) I get a compile error and says I can't bind to a ReadOnly property. The code below compiles, I've included (but rem'd out) the bits I've been trying in my attempts to get the property ReadOnly.
Can anyone assist please?
The Dependency Property of my overridden control looks like:
//public static readonly DependencyPropertyKey SelectedRowKey = DependencyProperty.RegisterReadOnly("SelectedObject", typeof(object), typeof(MyGrid), new PropertyMetadata(null));
//public static readonly DependencyProperty SelectedObjectProperty = SelectedRowKey.DependencyProperty;
public readonly static DependencyProperty SelectedObjectProperty = DependencyProperty.Register("SelectedObject", typeof(object), typeof开发者_运维技巧(MyGrid), new PropertyMetadata(null));
public object SelectedObject
{
get
{
return GetValue(SelectedObjectProperty);
}
set
{
throw new NotImplementedException();
}
}
The XAML is:
<StackPanel>
<devxgrid:MyGrid AutoPopulateColumns="True" DataSource="{Binding Animals}" SelectedObject="{Binding MyObject, Mode=OneWayToSource}" Width="300" Height="300">
<devxgrid:MyGrid.View>
<MyGrid:TableView AllowEditing="False" Name="GridView" AutoWidth="True" />
</devxgrid:MyGrid.View>
</devxgrid:MyGrid>
</StackPanel>
You're trying to set the SelectedObject
property in the XAML. If it's read-only, how can you set it?
Edit: sorry, my bad. Just realized what you're trying to do, and you're right that it should work. However, WPF doesn't support this scenario, at least in 3.5.
Edit 2: Just checked in .NET 4 and same story.
By the way, if you're stuck with someone else's readonly DP that you're trying to "push" into a VM, you can use an attached behavior to workaround this. For example, suppose you want your VM to be aware of the ActualWidth
and ActualHeight
properties of your view. You can write a SizeWatcherBehavior
that attaches to the FrameworkElement
and listens for size changes. When detected, those size changes are pushed to read/write attached properties that your VM can bind to:
<Grid local:SizeWatcherBehavior.Watch="True"
local:SizeWatcherBehavior.Width="{Binding WidthOnVM, Mode=OneWayToSource}"
local:SizeWatcherBehavior.Height="{Binding HeightOnVM, Mode=OneWayToSource}"/>
I'm a little late to this question considering it was asked almost 2 years ago :)
I made a solution to dynamically be able to push read-only dependency properties to the source called PushBinding
which I blogged about here. In your case it would look like this
<devxgrid:MyGrid AutoPopulateColumns="True"
DataSource="{Binding Animals}"
Width="300"
Height="300">
<pb:PushBindingManager.PushBindings>
<pb:PushBinding TargetProperty="SelectedObject" Path="MyObject"/>
</pb:PushBindingManager.PushBindings>
<!--...-->
</devxgrid:MyGrid>
PushBinding
works by using two Dependency Properties, Listener and Mirror. Listener is bound OneWay
to the TargetProperty and in the PropertyChangedCallback
it updates the Mirror property which is bound OneWayToSource
to whatever was specified in the Binding.
Demo Project can be Downloaded Here.
It contains source code and short sample usage, or visit my WPF blog if you're interested in the implementation details.
We are developing a custom control library, and one of our users filed a feature request to convert one of our DPs from Read-Only to Read-Write, because he did hit the same issue as you did - cannot bind OneWayToSource in an MVVM scenario.
Of course we did not make that DP read-write.
Using attached properties/behaviors for such scenarios is a huge overhead. The simplest workaround would be to handle the "SelectedObjectChanged" event in the code behind, and set the property that you wanted to bind to "SelectedObject" DP in the code behind.
In our opinion, this 'handle the event and call code from VM/DataContext directly' approach does not break MVVM in any way, since the ViewModel still does not know anything about the View.
The purists among us would otherwise expect that a true read-only DependencyProperty
scenario should ideally work as expected. But for apparent WPF one- and two-way data binding expectations, I agree along these lines.
However, I worked around this in my DependencyObject
view model by providing a full DependencyProperty
, but only providing a get-only property exposing the details I wanted. Not truly read-only in the WPF MVVM sense, but since I chose not to implement the setter, it works for my purposes.
I agree with other folks, any more code than that breaks MVVM in the strictest sense.
精彩评论