locked
Problem in WinRT :Items control with ItemsPanelTemplate as Canvas RRS feed

  • Question

  • This problem is in WinRT.

    I have a xmal file where I have N number of one type of present. It works fine. Then I decided to replace it with ItemsControl. Because it makes more sense.
    <ItemsControl  DataContext="{Binding NutList}" ItemsSource="{Binding}" Canvas.Top="100" Canvas.Left="100" behaviours:NutMoveFunctions.MonitorMove="True" Width="840" Height="810" >
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemContainerStyle>
                    <Style TargetType="ContentPresenter">
                        <Setter Property="Canvas.Top" Value="{Binding Top}"></Setter>
                        <Setter Property="Canvas.Left" Value="{Binding Left}"></Setter>
                    </Style>
                </ItemsControl.ItemContainerStyle>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <local:SingleNut Background="{Binding BackgroundImage, Converter={StaticResource BrushConverter}}" Width="194" Height="224" CacheMode="BitmapCache"   />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
    What I realized all N controls are at 0,0 on canvas.  Now if I remove ItemsControl.ItemsPanel it becomes default stack panel and I can see the all controls in a stack.

    I changed ItemsControl to listbox and TargetType="ListBoxItem”. The result is the same. All controls are at 0,0.
    What I doing wrong? How to fix it.
    Any help will be appreciated.


    Agha Khan

    Thursday, January 9, 2014 6:11 AM

Answers

  • Hi Agha,

    Databinding in the style setter as you are doing isn't supported and so your Canvas.Top and Left bindings are ignored, leaving the items at 0,0. You should be able to set up the binding in the ItemsControl.PrepareContainerForItemOverride method .

    public class MyItemsControl : ItemsControl
    { 
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item) 
        { 
            base.PrepareContainerForItemOverride(element, item); 
            FrameworkElement source = element as FrameworkElement; 
            source.SetBinding(Canvas.Top, new Binding { Path = new PropertyPath("Top") }); 
            source.SetBinding(Canvas.Left, new Binding { Path = new PropertyPath("Left") }); 
        } 
    }

    This is the same behavior as Silverlight, so you may be able to use methods devised for the same scenario in Silverlight apps as well. I haven't tried it, but take a look at http://blogs.msdn.com/b/delay/archive/2009/11/02/as-the-platform-evolves-so-do-the-workarounds-better-settervaluebindinghelper-makes-silverlight-setters-better-er.aspx .

    --Rob

    Friday, January 10, 2014 1:20 AM
    Moderator
  • Thank you Rob.

    It worked.

           protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
            {
                base.PrepareContainerForItemOverride(element, item);
                FrameworkElement source = element as FrameworkElement;
                if (source != null)
                {
                    source.SetBinding(Canvas.TopProperty, new Windows.UI.Xaml.Data.Binding {Path = new PropertyPath("Top")});
                    source.SetBinding(Canvas.LeftProperty, new Windows.UI.Xaml.Data.Binding { Path = new PropertyPath("Left") });
                }
            } 


    Agha Khan

    Friday, January 10, 2014 9:00 PM

All replies

  • Hi Agha,

    Databinding in the style setter as you are doing isn't supported and so your Canvas.Top and Left bindings are ignored, leaving the items at 0,0. You should be able to set up the binding in the ItemsControl.PrepareContainerForItemOverride method .

    public class MyItemsControl : ItemsControl
    { 
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item) 
        { 
            base.PrepareContainerForItemOverride(element, item); 
            FrameworkElement source = element as FrameworkElement; 
            source.SetBinding(Canvas.Top, new Binding { Path = new PropertyPath("Top") }); 
            source.SetBinding(Canvas.Left, new Binding { Path = new PropertyPath("Left") }); 
        } 
    }

    This is the same behavior as Silverlight, so you may be able to use methods devised for the same scenario in Silverlight apps as well. I haven't tried it, but take a look at http://blogs.msdn.com/b/delay/archive/2009/11/02/as-the-platform-evolves-so-do-the-workarounds-better-settervaluebindinghelper-makes-silverlight-setters-better-er.aspx .

    --Rob

    Friday, January 10, 2014 1:20 AM
    Moderator
  • Thank you Rob.

    It worked.

           protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
            {
                base.PrepareContainerForItemOverride(element, item);
                FrameworkElement source = element as FrameworkElement;
                if (source != null)
                {
                    source.SetBinding(Canvas.TopProperty, new Windows.UI.Xaml.Data.Binding {Path = new PropertyPath("Top")});
                    source.SetBinding(Canvas.LeftProperty, new Windows.UI.Xaml.Data.Binding { Path = new PropertyPath("Left") });
                }
            } 


    Agha Khan

    Friday, January 10, 2014 9:00 PM