Ok I have a container that I have created two data templates for. Basically one template will show 5 textboxes with and objects data bound to them and the other template will show a button to add that particular object. I subclassed DataTemplateSelector and it works, but when I navigate through my records the Selector never gets called again.
So how would I for the container to reselect it's template. The container is a StackPanel and I have already tried UpdateVisuals, InvalidateVisuals, InvalidateArrange, and ApplyTemplate.
XAML Code
<DataTemplate x:Key="advisorTemplate">
<StackPanel Orientation="Vertical" Margin="2,2,2,2" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<StackPanel Orientation="Horizontal" Margin="2,2,2,2" HorizontalAlignment="Center">
<extToolkit:WatermarkTextBox Name="txtAcadAdv" Watermark="Acad Adv" Width="125" Margin="2" Text="{Binding Path=Adv.AcadAdv}"/>
<extToolkit:WatermarkTextBox Name="txtProgAdv" Watermark="Prog Adv" Width="125" Margin="2" Text="{Binding Path=Adv.ProgAdv}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="2,2,2,2" HorizontalAlignment="Center">
<extToolkit:WatermarkTextBox Name="txtPortAdv" Watermark="Port Adv" Width="125" Margin="2" Text="{Binding Path=Adv.PortAdv}"/>
<extToolkit:WatermarkTextBox Name="txtEleTws" Watermark="Ele Tws" Width="125" Margin="2" Text="{Binding Path=Adv.EleTws}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="2,2,2,2" HorizontalAlignment="Center">
<extToolkit:WatermarkTextBox Name="txtMatTws" Watermark="Mat Tws" Width="125" Margin="2" Text="{Binding Path=Adv.MatTws}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="addAdvisor">
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2" Name="btnAddAdvisor" Click="ButtonClick" Content="Add Advisor"/>
</DataTemplate>
Initialization of the Content Changed on the Group Box
grpAdv.ContentTemplateSelector = _advisorSelector;
And Finally the Selector Code
private readonly StudentWin _win;
public AdvisorDataTemplateSelector(StudentWin win)
{
_win = win;
}
public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
{
var sp = item as StackPanel;
var adv = sp.DataContext as Advisor;
if (adv == null)
return _win.FindResource("addAdvisor") as DataTemplate;
return _win.FindResource("advisorTemplate") as DataTemplate;
}
And Here is a snippet of my navigation code
case "btnNext":
{
if(_view.CurrentPosition < _view.Count - 1)
{
CheckForUnusedReferences(_view.GetItemAt(_view.CurrentPosition) as Student);
_view.MoveCurrentToNext();
CheckForNullReferences(_view.CurrentPosition);
grpAdv.ApplyTemplate();
}
}
The two additional Methods are to check if a relationship is null on the student and they will create it and add it to the data context for me or else Entity Framework won't save the changes. The data templates above will basically help me with a problem of not having the studentId when I try to create a new student.
I've used the following method to force re-application of a DataTemplateSelector.
Derive from ObservableCollection and add a method that raises NotifyCollectionChangedEventArgs with NotifyCollectionChangedAction.Reset.
public class MyThingCollection : ObservableCollection<MyThing>
{
public void RaiseResetCollection()
{
OnCollectionChanged(new
NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
Your view model exposes an instance of this type and your ItemsControl binds to that.
public class MyViewModel : ... (view model base)
{
public MyThingCollection Items{get; private set;}
}
<ItemsControl
ItemsSource="{Binding Items}"
ItemsTemplateSelector="{StaticResource MyTemplateSelector}"
...
When you need your DataTemplateSelector to be re-applied call RaiseResetCollection on the collection.
I generally use DataTemplateSelector like this
public class MyTemplateSelector : DataTemplateSelector
{
public DataTemplate Template1 { get; set; }
public DataTemplate Template2 { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
... return Template1 or Template2 depending on item
}
...
}
<DataTemplate x:Key="MyTemplate1" DataType="{x:Type MyType1}">
...
</DateTemplate>
<DataTemplate x:Key="MyTemplate2" DataType="{x:Type MyType2}">
...
</DateTemplate>
<local:MyTemplateSelector
x:Key="MyTemplateSelector"
Template1="{StaticResource MyTemplate1}"
Template2="{StaticResource MyTemplate2}"
/>
来源:https://stackoverflow.com/questions/10741547/dynamically-load-content-with-wpf