Search code examples
wpfxamlmvvmbindingdatacontext

DataContext not binding in Style.Trigger


So I have some code similar to the following: (Forgive any typos-- I tried to simplify in the SO editor for the post)

<my:CustomContentControl>
        <my:CustomContentControl.Style>
            <Style TargetType="{x:Type my:CustomContentControl}">
                <Style.Triggers>                        
                    <DataTrigger Binding="{Binding Path=CurrentView}" Value="MyCustomView">
                        <Setter Property="Content">
                            <Setter.Value>
                                <my:CustomView DataContext="{Binding DataContextForMyCustomView"/>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </m:CustomContentControl.Style>
</my:CustomContentControl>

The problem is that whenever the DataTrigger occurs, the setter does set the Content property to my:CustomView, but it does not bind DataContext. If I move the same code outside of the trigger the DataContext binding works just fine.

Any ideas? If this is a limitation of some sorts, is there any work around?

Update:

I received the following error in the output window:

System.Windows.Data Error: 3 : Cannot find element that provides DataContext. BindingExpression:Path=DataContextForMyCustomView; DataItem=null; target element is 'CustomView' (Name='customView'); target property is 'DataContext' (type 'Object')


Solution

  • The error you posted makes it sound like your custom control is in an object that doesn't have a DataContext, such as a DataGridColumn.Header.

    To get around that, you can create a Freezeable object in your .Resources containing the binding you're looking for, then bind your my:CustomView.DataContext to that object

    <my:CustomContentControl.Resources>
        <local:BindingProxy x:Key="proxy" 
            Data="{Binding DataContextForMyCustomView, ElementName=MyControl}" />
    </my:CustomContentControl.Resources>
    
    ...
    
    <my:CustomView DataContext="{Binding Source={StaticResource proxy}}"/>
    

    Here's the code for a sample Freezable object copied from here:

    public class BindingProxy : Freezable
    {
        #region Overrides of Freezable
    
        protected override Freezable CreateInstanceCore()
        {
            return new BindingProxy();
        }
    
        #endregion
    
        public object Data
        {
            get { return (object)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }
    
        // Using a DependencyProperty as the backing store for Data.  
        // This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object), 
                typeof(BindingProxy), new UIPropertyMetadata(null));
    }
    

    Also, you really should use ContentTemplate instead of Content to avoid an exception if more than one object applies that style :)