locked
Binding to the type of an Ancestor's datacontext RRS feed

  • Question

  •  Hi, 

    In the simplest case i have a Model which has a Member,both have types have typed datatemplates. i'd like to bind property from Model within the Member template.

    I like to do this with the relativesource constuct but it doesn't work since this looks for the type of parent uielement's not the type of the  DataContext in parent ContentPresenter's which Model and Member are wrapped in by the typed datatemplates

    Xaml

      <Window.Resources>
            <DataTemplate DataType="{x:Type this:Model}">
                <StackPanel>
                    <Label Content="{Binding ModelName}"/>
                    <Label Content="{Binding Member}"/>
                </StackPanel>
            </DataTemplate>
            <DataTemplate DataType="{x:Type this:Member}">
                <StackPanel>
                    <Label Content="{Binding MemberName}"/>
                   
                    <!--works but nasty syntax and isn't practicle for deep nested classes-->
                    <Label Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Parent.DataContext.ModelName}"/>
                    <!-- This doesn't work since this looks for the type of the uielements not the type of  DataContext in a contentPresenter which Model and Member are wrapped in by the typed template-->
                    <Label Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type this:Model}}, Path=ModelName}"/>
                </StackPanel>
            </DataTemplate>
        </Window.Resources>
        <Grid>
            <Label Content="{Binding Model}"/>
        </Grid>

    code:

     public class Model
        {
            public string ModelName { get; set; }
            public Member Member { get; set; }
        }

        public class Member
        {
            public string MemberName { get; set; }              
        }


        public partial class Window1 : Window
        {
            public Model Model { get; set; }
            public Window1()
            {
                InitializeComponent();


                var m = new Model()
                {
                    ModelName = "model",
                    Member = new Member()
                    {
                        MemberName = "member"
                    }
                };
                Model = m;
                DataContext = this;
            }
        }

    Can anyone point me in the right direction to solve this problem or direct me how to write a custom markup extension that will solve this problem.

    Thanks,
    Paul


    nanopass
    • Edited by xepaul2 Friday, September 26, 2008 5:48 PM better title
    Thursday, September 25, 2008 11:44 PM

Answers

  • I have found a tempory solution to this problem by wrapping the root of Model in the special marker content control.

    This shows a better sample. A model contains a command and a member, the member is rendered by a member typed datatemplate, within the member a button is rendered to save it with is binded to the command in the model. This is a simple example but the basic idea works for deeply nested classes, where the model holds commands and any additional data that need to be bound to nested classes.

    If you have a better solution to this please post.

    Paul

        <Window.Resources>
            <DataTemplate DataType="{x:Type this:Model}">
                <DataTemplate.Resources>
                    <DataTemplate DataType="{x:Type this:Member}">
                        <StackPanel>
                            <Label Content="{Binding MemberName}"/>
                            <Button Content="Save" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type this:ContentControlMarker}}, Path=DataContext.SaveCommand}"/>
                        </StackPanel>
                    </DataTemplate>
                </DataTemplate.Resources>
                <this:ContentControlMarker>
                    <StackPanel>
                        <ContentControl Content="{Binding Member}"/>
                    </StackPanel>
                </this:ContentControlMarker>
            </DataTemplate>      
        </Window.Resources>
        <Grid>

        </Grid>


      public class ContentControlMarker : ContentControl
        {
        }

        public class Model
        {
           
            public Member Member { get; set; }
            public ICommand SaveCommand { get; set; }
        }

        public class Member
        {
            public string MemberName { get; set; }
        }

        public partial class Window1 : Window
        {  
            public Window1()
            {
                InitializeComponent();

                var m = new Model()
                {                
                    Member = new Member()  { MemberName = "memberName" },
                    SaveCommand = new DelegateCommand<object>(
                        p=> {
                            //Save Member
                            int i=0;
                            })
                };
                this.Content = m;
            }
        }

    nanopass
    Friday, September 26, 2008 5:46 PM