Reputation: 6116
I have a dialog window that contains a ListBox
whose ItemTemplate contains an expander.
Its IsExpanded
is bound to a property in the item view model. The ListBoxItem
's IsSelected
property is also bound to the IsExpanded
property in the item view model object. And finally the SelectedItem
property of the ListBox
is bound to a property with the same name in the view model.
The problem here is that when setting up the view model before showing the dialog and setting it to the DataContext
of the dialog, the item in the listbox gets selected as it should, the expander arrow shows that it is in the expanded state, but the content of the expander is not displayed.
If I set up the view model after showing the dialog, eg. in the Loaded handler of the dialog things work as expected. What is going on here, and what would be the best way to fix it?
The dialog window is defined as:
<Window x:Class="WpfApplication1.Dialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:WpfApplication1"
Title="Dialog" Height="300" Width="300">
<Grid>
<ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<Expander Header="Expander" x:Name="MyExpander" IsExpanded="{Binding IsExpanded, Mode=TwoWay}">
<Rectangle Width="100" Height="20" Fill="Red" />
</Expander>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding IsExpanded, Mode=TwoWay}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
And the ViewModel (implementation not included for the sake of brevity):
public interface IMyViewModel : INotifyPropertyChanged
{
object SelectedItem { get; set; }
ObservableCollection<IMyItemViewModel> Items { get; }
}
public interface IMyItemViewModel : INotifyPropertyChanged
{
bool IsExpanded { get; set; }
}
Then I have a simple main window with a button, and its Click
handler is defined as:
private void Button_Click(object sender, RoutedEventArgs e)
{
MyViewModel vm = new MyViewModel();
MyItemViewModel item = new MyItemViewModel();
vm.Items.Add(item);
vm.SelectedItem = item;
Dialog dialog = new Dialog();
dialog.DataContext = vm;
dialog.ShowDialog();
}
When I run the application and click the button, the dialog shows up, the expander arrow indicates that it is in the expanded state, but its content is not displayed. Clicking on the expander collapses it, and clicking it again expands it, this time showing the content. Putting the same code directly in the Main Window instead of a dialog however works as it is supposed to.
If I just do a Dispatcher.BeginInvoke(new Action(() => vm.SelectedItem = item);
instead of setting it directly things also seem to work, but this feels a bit shaky.
What can be done to fix this problem?
Upvotes: 2
Views: 1268
Reputation: 12319
Sounds like the content of the expander is not measured again after it is loaded, if the IsExpanded
property is already set to true. Or to put it another way, the content is measured when it has still no actual size.
I suppose the easiest solution would be to just set the SelectedItem
once the dialog has been loaded:
dialog.Loaded += (s, x) => vm.SelectedItem = item;
Upvotes: 2