How do I access the datacontext of a silverlight control in the codebehind
I've a silverlight control I am instantiating like so:
<MyControls:SomeControl DataContext="{Binding}" />
In the codebehind of this file, how can I get access to this datacontext? this.DataContext is equal to null.
Edit (more info):
I am building an extension for an existing silverlight application. My point where I integrate with the app looks like this:
<DataTemplate x:Key="AnImportantIdentifierUsedByTheHostApp">
<MyControls:SomeControl DataContext="{Binding}" />
</DataTemplate>
Inside my control, I am able to bind against properties like so:
<Hyperlink NavigateUri="{Binding Path=UriWithSlug}">
And this all works fine. However for certain functionality (specifically, I need to use a WebBrowser control and the NavigateToString() method), I need to access properties from the DataContext.
Basically in the codebehind, I need to do something to the effect of:
myWebBrowser.开发者_C百科NavigateToString(DataContext.MyHTMLStringProperty);
You don't need DataContext={Binding}
since that is tantamount to DataContext = DataContext
.
However what you are missing is type information. Bindings use reflection to resolve property paths, however in code-behind you will need to know the type of the object returned by DataContext
.
If you can be sure of that then it would simply be:-
myWebBrowser.NavigateToString(((MyType)DataContext).MyHTMLString);
If you can't be sure of the type and/or you can't persuade whoever controls the host of your controls to ensure at least a specific Interface with known members is implemented, then you might need to resort to reflection yourself.
Use the binding system to do the reflection for you
An alternative if you can't know the type only the name of the property:-
public string HTMLString
{
get { return (string)GetValue(HTMLStringProperty); }
set { SetValue(HTMLStringProperty, value); }
}
public static DependencyProperty HTMLStringPropery =
DependencyProperty.Register(
"HTMLString",
typeof(string),
typeof(SomeControl),
null);
Now if you are sure you know the name of the property you want to bind you can set up the binding in code in your controls constructor:-
SetBinding(HTMLStringProperty, new Binding("MyHTMLString"));
With this in place your code would look like:-
myWebBrowser.NavigateToString(HTMLString);
Alternatively you would make binding this new property of your control the responsibility of the Xaml:-
<DataTemplate x:Key="AnImportantIdentifierUsedByTheHostApp">
<MyControls:SomeControl HTMLString="{Binding MyHTMLString}" />
</DataTemplate>
The answer of course is super straight forward and something I'm sure everyone probably assumed I was doing...
The DataContext is not available until the control's Loaded
event has fired.
public MyUserControl() {
var dc = this.DataContext // DataContext is null here in the ctor.
this.Loaded += (s, e) => {
var sc2 = this.DataContext // Loaded event fires, DataContext exists!
};
}
Again, I'm sure this is probably obvious to a lot of SL devs but it completely tripped me up.
Ok, makes a little more sense now. Changing answer accordingly...
Basically you should never need DataContext={Binding}. The DataContext of an item is set (per item) by the parent control. In most list-type controls that is generated from the entries in the ItemsSource.
- Can you remove the DataContext={Binding} and check that it still works?
- If the actual child control has no explicit DataContext value itself, then to get the DataContext of a parent control you may have to navigate up the visual tree (until you find a non-null DataContext).
Can you provide more of the code/xaml we we can see the above in context?
var mytype = this.DataContext as MyType;
As a precaution, I'll check for null afterwards:
if (mytype!=null)
{
// do something here
myWebBrowser.NavigateToString(mytype.MyHTMLStringProperty);
}
精彩评论