In Silverlight 3 and higher you can use Element to Element binding and point to the controls DataContext and then some property in my example its Threshold property.
So first name your control (for example in my example its x:Name="control")
<UserControl x:Class="SomeApp.Views.MainPageView" x:Name="control" >
then inside this control in your ListBox ItemTemplate you can access parent DataContext like this:
<ListBox ItemsSource="{Binding Path=SomeItems}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ElementName=control, Path=DataContext.Threshold}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In WPF, we don't generally set the DataContext
of a Window
to one data type object like this... however it is possible. Instead, we normally create a specific class that contains all of the properties required to be displayed and as you alluded to, implements the INotifyPropertyChanged
interface. In your case, we would have a property of type Staff
that we could bind to in the UI:
public string Staff
{
get { return staff; }
set { staff = value; NotifyPropertyChanged("Staff"); }
}
Then in XAML:
<Window>
<StackPanel>
<TextBox Text="{Binding Staff.Id}"/>
<TextBox Text="{Binding Staff.Name}"/>
</StackPanel>
</Window>
In this small example, this is not strictly necessary, but in larger projects, it is likely that there would be other data to display as well. If you set the Window.DataContext
to just one instance of your Staff
data type, then you would find it tricky to display other data, such as a collection of Staff
objects. Likewise, it is better to update the Staff
property, which will inform the interface to update the UI, rather than the DataContext
which will not update the UI as it is not 'connected' to the interface.
It is the notification of property changes through the INotifyPropertyChanged
interface that updates, or 'refreshes as you call it, the values in the UI controls when property changes are made. So your answer is to implement this interface and make sure that you call the INotifyPropertyChanged.PropertyChangedEventHandler
when property value changes are made.
UPDATE >>>
Wow! You really aren't listening, are you? In WPF, we don't 'refresh' the DataContext
, the INotifyPropertyChanged
interface 'refreshes' the UI once properties have been changed. This is one possible way that you could fix this problem:
public class CustomObject
{
public int Id { get; set; }
public string Name { get; set; }
...
}
...
Dictionary<string, string> data = new Dictionary<string, string>
{
{"ID_Id", "1"},
{"ID_Name", "John"}
...
};
...
// Implement the `INotifyPropertyChanged` interface on this property
public ObservableCollection<CustomObject> CustomObjects { get; set; }
...
You could then fill your CustomObject
like this:
CustomObjects = new ObservableCollection<CustomObject>();
CustomObject customObject = new CustomObject();
foreach (KeyValuePair<string, string> entry in data)
{
if (entry.Key == "ID_Id") // Assuming this always comes first
{
customObject = new CustomObject();
customObject.Id = int.Parse(entry.Value);
}
...
else if (entry.Key == "ID_Name") // Assuming this always comes lasst
{
customObject.Name = entry.Value;
customObjects.Add(customObject);
}
}
...
<ListBox ItemsSource="{Binding CustomObjects}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type DataTypes:CustomObject}">
<StackPanel>
<TextBox Text="{Binding Id}"/>
...
<TextBox Text="{Binding Name}"/>
</StackPanel>
</DataTemplate DataType="{x:Type DataTypes:CustomObject}">
</ListBox.ItemTemplate>
</Window>
Now you could argue that you can't do this for this reason, or you don't want to do that for that reason, but at the end of the day, you have to do something like this to solve your problem.
Best Answer
Well, I've learned more about this... This whole thing is a Master-Detail UI design, and so I had my ListBox using SelectedItem="{Binding ActivePattern}", and apparently, some infinite loop was getting set up between that and the SelectionChanged eventhandler.
So now my question now becomes what good is SelectedItem anyway? Since I had to add a SelectionChanged eventhandler to update the DataContext of the detail stack panel?