I want to enlarge (let it take whole available space) a part of window content temporarily.
Window layout is pretty complicated: many nested panels, splitters, content to enlarge is 10 levels deep. Changing Visibility
to stretch content is simply not enough (thanks to splitters) and seems very complicated.
I decide to move that content into a user control and do something like (pseudo-code)
if(IsEnlarged)
{
oldContent = window.Content; // store
window.Content = newContent;
}
else
window.Content = oldContent; // restore
No problems. It was working perfectly in test project ... until I start using data templates.
Problem: if data templates are used then as soon as window.Content = newContent
occurs, then that newContent.DataContext
is lost and become the same as window.DataContext
. This will trigger various binding errors, attached behaviors suddenly changes to default value, etc.. all kind of bad stuff.
DataContext
is changing? How to prevent/fix this issue?Here is a repro (sorry, can't make it any shorter):
MainWindow.xaml contains
<Window.Resources>
<DataTemplate DataType="{x:Type local:ViewModel}">
<local:UserControl1 />
</DataTemplate>
</Window.Resources>
<Grid Background="Gray">
<ContentControl Content="{Binding ViewModel}" />
</Grid>
MainWindow.cs contains
public ViewModel ViewModel { get; } = new ViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
UserControl1.xaml contains
<Button Width="100"
Height="100"
CommandParameter="{Binding RelativeSource={RelativeSource Self}}"
Command="{Binding Command}" />
ViewModel (using DelegateCommand)
public class ViewModel
{
public DelegateCommand Command { get; set; }
bool _set;
object _content;
public ViewModel()
{
Command = new DelegateCommand(o =>
{
var button = (Button)o;
var window = Window.GetWindow(button);
_set = !_set;
if (_set)
{
_content = window.Content;
var a = button.DataContext; // a == ViewModel
window.Content = button;
var b = button.DataContext; // b == MainWindow ??? why???
}
else
window.Content = _content;
});
}
}
Set breakpoint on var a = ...
, start program, click the button, do steps and observe button.DataContext
as well as binding error in Output
window.
ok here some general thoughts.
if you bind a object(viewmodel) to the Content property of the contentcontrol then wpf uses a DataTemplate to visualize the object. if you dont have a DataTemplate you just see object.ToString(). DataContext inheritance means that the DataContext is inherited to the child elements. so a real usercontrol will inherit the DataContext from the parent. the are common mistakes you find here on stackoverflow when creating UserControls - they often break DataContext inheritance and set the DataContext to self or a new DataContext.