Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. WPF
  4. WPF Binding to an attached property from a DataTemplate [modified]

WPF Binding to an attached property from a DataTemplate [modified]

Scheduled Pinned Locked Moved WPF
wpfcsharpcsswcfcom
7 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Mark Salsbery
    wrote on last edited by
    #1

    Is there a good way to bind an element created through a DataTemplate to an attached property? Please refer to this post[^] for full source code (scroll down to around the smiley)... Elements are created through a DataTemplate and end up as children of a Grid. The data has Row and Col properties that need to be bound to the Grids Row and Column attached properties. The most obvious binding (to me) would be something like this:

                        <DataTemplate DataType="{x:Type local:Obs}">
                            <Button `Grid.Row="{Binding Path=Row}" Grid.Column="{Binding Path=Col}"` Click="Button\_Click">
                                <Button.Style>
                                    <Style TargetType="{x:Type Button}" >
                                        <Setter Property="Content" Value="{Binding Path=Name}"/>
                                        <Setter Property="Width" Value="50"/>
                                        <Setter Property="Height" Value="Auto"/>
                                        <Setter Property="Margin" Value="2"/>
                                        <Setter Property="Background" Value="#FFBBBB00"/>
                                        <Setter Property="Foreground" Value="#FF000000"/>
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding Path=Status}" Value="On">
                                                <Setter Property="Background" Value="#FFFFFF00"/>
                                                <Setter Property="Foreground" Value="#FFFF0000"/>
                                            </DataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                </Button.Style>
                            </Button>
                        </DataTemplate>
    

    but it doesn't work, I assume because the element isn't yet a child of the grid at the time the binding is created. Based on that assumption, I figured I needed an event of some kind to give me a chance to do the binding once the created element is a child of the

    T G 2 Replies Last reply
    0
    • M Mark Salsbery

      Is there a good way to bind an element created through a DataTemplate to an attached property? Please refer to this post[^] for full source code (scroll down to around the smiley)... Elements are created through a DataTemplate and end up as children of a Grid. The data has Row and Col properties that need to be bound to the Grids Row and Column attached properties. The most obvious binding (to me) would be something like this:

                          <DataTemplate DataType="{x:Type local:Obs}">
                              <Button `Grid.Row="{Binding Path=Row}" Grid.Column="{Binding Path=Col}"` Click="Button\_Click">
                                  <Button.Style>
                                      <Style TargetType="{x:Type Button}" >
                                          <Setter Property="Content" Value="{Binding Path=Name}"/>
                                          <Setter Property="Width" Value="50"/>
                                          <Setter Property="Height" Value="Auto"/>
                                          <Setter Property="Margin" Value="2"/>
                                          <Setter Property="Background" Value="#FFBBBB00"/>
                                          <Setter Property="Foreground" Value="#FF000000"/>
                                          <Style.Triggers>
                                              <DataTrigger Binding="{Binding Path=Status}" Value="On">
                                                  <Setter Property="Background" Value="#FFFFFF00"/>
                                                  <Setter Property="Foreground" Value="#FFFF0000"/>
                                              </DataTrigger>
                                          </Style.Triggers>
                                      </Style>
                                  </Button.Style>
                              </Button>
                          </DataTemplate>
      

      but it doesn't work, I assume because the element isn't yet a child of the grid at the time the binding is created. Based on that assumption, I figured I needed an event of some kind to give me a chance to do the binding once the created element is a child of the

      T Offline
      T Offline
      Timmy Kokke
      wrote on last edited by
      #2

      Inside a datatemplate you can bind to a relative source, a parent, of the object by using the RelativeSource attribute. You should try and experiment with something like:

      <DataTemplate DataType="{x:Type local:Obs}">
      <Button Grid.Row="{Binding Path=Row, RelativeSource={RelativeSource AncestorType={x:Type Grid}}}"
      Grid.Column="{Binding Path=Col, RelativeSource={RelativeSource AncestorType={x:Type Grid}}}"
      Click="Button_Click">
      ..

      Good Luck!

      Dawn is nature's way of telling you to go to bed.

      M 1 Reply Last reply
      0
      • T Timmy Kokke

        Inside a datatemplate you can bind to a relative source, a parent, of the object by using the RelativeSource attribute. You should try and experiment with something like:

        <DataTemplate DataType="{x:Type local:Obs}">
        <Button Grid.Row="{Binding Path=Row, RelativeSource={RelativeSource AncestorType={x:Type Grid}}}"
        Grid.Column="{Binding Path=Col, RelativeSource={RelativeSource AncestorType={x:Type Grid}}}"
        Click="Button_Click">
        ..

        Good Luck!

        Dawn is nature's way of telling you to go to bed.

        M Offline
        M Offline
        Mark Salsbery
        wrote on last edited by
        #3

        I've experimented for HOURS on this :) Anyway, that doesn't work in the context of the code I linked to (a DataTemplate for an ItemsControl ItemsTemplate)...tried it already, and tried it again. I do appreciate the help, thanks! Mark

        Mark Salsbery Microsoft MVP - Visual C++ :java:

        T 1 Reply Last reply
        0
        • M Mark Salsbery

          Is there a good way to bind an element created through a DataTemplate to an attached property? Please refer to this post[^] for full source code (scroll down to around the smiley)... Elements are created through a DataTemplate and end up as children of a Grid. The data has Row and Col properties that need to be bound to the Grids Row and Column attached properties. The most obvious binding (to me) would be something like this:

                              <DataTemplate DataType="{x:Type local:Obs}">
                                  <Button `Grid.Row="{Binding Path=Row}" Grid.Column="{Binding Path=Col}"` Click="Button\_Click">
                                      <Button.Style>
                                          <Style TargetType="{x:Type Button}" >
                                              <Setter Property="Content" Value="{Binding Path=Name}"/>
                                              <Setter Property="Width" Value="50"/>
                                              <Setter Property="Height" Value="Auto"/>
                                              <Setter Property="Margin" Value="2"/>
                                              <Setter Property="Background" Value="#FFBBBB00"/>
                                              <Setter Property="Foreground" Value="#FF000000"/>
                                              <Style.Triggers>
                                                  <DataTrigger Binding="{Binding Path=Status}" Value="On">
                                                      <Setter Property="Background" Value="#FFFFFF00"/>
                                                      <Setter Property="Foreground" Value="#FFFF0000"/>
                                                  </DataTrigger>
                                              </Style.Triggers>
                                          </Style>
                                      </Button.Style>
                                  </Button>
                              </DataTemplate>
          

          but it doesn't work, I assume because the element isn't yet a child of the grid at the time the binding is created. Based on that assumption, I figured I needed an event of some kind to give me a chance to do the binding once the created element is a child of the

          G Offline
          G Offline
          Gideon Engelberth
          wrote on last edited by
          #4

          The reason why this does not work is because the ItemsControl wraps your object in a container. To get the binding you want you will need to make an StyleSelector to assign to the ItemContainerStyleSelector property of the Items control. Something like this should work:

          Public Overrides Function SelectStyle(ByVal item As Object,
          ByVal container As System.Windows.DependencyObject)
          As System.Windows.Style
          Dim matElem As Obs = TryCast(item, Obs)

          Dim ret As New Style()
          If matElem IsNot Nothing Then
              ret.Setters.Add(New Setter(Grid.RowProperty, matElem.PositionY))
              ret.Setters.Add(New Setter(Grid.ColumnProperty, matElem.PositionX))
          End If
          
          Return ret
          

          End Function

          M 1 Reply Last reply
          0
          • M Mark Salsbery

            I've experimented for HOURS on this :) Anyway, that doesn't work in the context of the code I linked to (a DataTemplate for an ItemsControl ItemsTemplate)...tried it already, and tried it again. I do appreciate the help, thanks! Mark

            Mark Salsbery Microsoft MVP - Visual C++ :java:

            T Offline
            T Offline
            Timmy Kokke
            wrote on last edited by
            #5

            My fault... I misread your post, I guess I was working a bit too late... :zzz: Anyway, I just recreated a solution based on your code in a previous post. I do not entirely understand what you're trying to do... When I click the Test button, button 3 moves to the first column and a 6th button is added to the grid. Like this:Screenshot[^]. Is this what is supposed to happen? If not, could you explain a bit more about what should happen.

            Dawn is nature's way of telling you to go to bed.

            M 1 Reply Last reply
            0
            • T Timmy Kokke

              My fault... I misread your post, I guess I was working a bit too late... :zzz: Anyway, I just recreated a solution based on your code in a previous post. I do not entirely understand what you're trying to do... When I click the Test button, button 3 moves to the first column and a 6th button is added to the grid. Like this:Screenshot[^]. Is this what is supposed to happen? If not, could you explain a bit more about what should happen.

              Dawn is nature's way of telling you to go to bed.

              M Offline
              M Offline
              Mark Salsbery
              wrote on last edited by
              #6

              Timmy Kokke wrote:

              Is this what is supposed to happen?

              Yes :) I was demonstrating to the OP how changing the data would reflect in the UI - the test showed you can change the cell position of existing objects in the collection and add items to the collection. The code I posted works like I wanted it to....I just didn't like the way I did the binding from the data object's Row and Col properties to the Grid.Row and Grid.Column attached properties, and I could't figure out a better way, so I started this new thread. Cheers, Mark

              Mark Salsbery Microsoft MVP - Visual C++ :java:

              modified on Saturday, November 15, 2008 12:51 PM

              1 Reply Last reply
              0
              • G Gideon Engelberth

                The reason why this does not work is because the ItemsControl wraps your object in a container. To get the binding you want you will need to make an StyleSelector to assign to the ItemContainerStyleSelector property of the Items control. Something like this should work:

                Public Overrides Function SelectStyle(ByVal item As Object,
                ByVal container As System.Windows.DependencyObject)
                As System.Windows.Style
                Dim matElem As Obs = TryCast(item, Obs)

                Dim ret As New Style()
                If matElem IsNot Nothing Then
                    ret.Setters.Add(New Setter(Grid.RowProperty, matElem.PositionY))
                    ret.Setters.Add(New Setter(Grid.ColumnProperty, matElem.PositionX))
                End If
                
                Return ret
                

                End Function

                M Offline
                M Offline
                Mark Salsbery
                wrote on last edited by
                #7

                Excellent Gideon, thank you! StyleSelector is news to me :) I actually needed bindings, not just setters for the initial value, but I'm much more comfortable setting them in the item style selector than in the grid ArrangeOverride like I was doing in my hacked solution. This is a much more appropriate place to set the bindings and I was able to remove the silly IsBoundToUI flag from the data object class. Here's what I did:

                public class ObsItemStyleSelector : StyleSelector
                {
                    public override Style SelectStyle(object item, DependencyObject container)
                    {
                        Obs obs = item as Obs;
                        ContentPresenter cp = container as ContentPresenter;
                
                        if (null != obs && null != cp)
                        {
                            Binding binding = new Binding("Row");
                            binding.Source = obs;
                            cp.SetBinding(Grid.RowProperty, binding);
                
                            binding = new Binding("Col");
                            binding.Source = obs;
                            cp.SetBinding(Grid.ColumnProperty, binding);
                        }
                
                        return null;
                    }
                }
                

                That works well! Thanks again, Mark

                Mark Salsbery Microsoft MVP - Visual C++ :java:

                1 Reply Last reply
                0
                Reply
                • Reply as topic
                Log in to reply
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes


                • Login

                • Don't have an account? Register

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • World
                • Users
                • Groups