0
votes

I created my own Custom control with its own DependencyProperty ItemsSource It dynamically creates buttons based on the amount of items supplied in a bound list. When creating the XAML I should be able to bind a list to my custom control by declaring

ItemsSource="{Binding ListOfData}". 

I can't seem to get it display the buttons or show, is the data not binding to the list properly?


         [TemplateVisualState(GroupName = "Button0States", Name = "Button0Visible")]
         [TemplateVisualState(GroupName = "Button0States", Name = "Button0NotVisible")]
         [TemplateVisualState(GroupName = "Button1States", Name = "Button1Visible")]
         [TemplateVisualState(GroupName = "Button1States", Name = "Button1NotVisible")]
         [TemplateVisualState(GroupName = "Button2States", Name = "Button2Visible")]
         [TemplateVisualState(GroupName = "Button2States", Name = "Button2NotVisible")]
         [TemplateVisualState(GroupName = "Button3States", Name = "Button3Visible")]
         [TemplateVisualState(GroupName = "Button3States", Name = "Button3NotVisible")]
         [TemplateVisualState(GroupName = "Button4States", Name = "Button4Visible")]
         [TemplateVisualState(GroupName = "Button4States", Name = "Button4NotVisible")]
         [TemplateVisualState(GroupName = "Button5States", Name = "Button5Visible")]
         [TemplateVisualState(GroupName = "Button5States", Name = "Button5NotVisible")]
         [TemplateVisualState(GroupName = "Button6States", Name = "Button6Visible")]
         [TemplateVisualState(GroupName = "Button6States", Name = "Button6NotVisible")]
         [TemplateVisualState(GroupName = "Button7States", Name = "Button7Visible")]
         [TemplateVisualState(GroupName = "Button7States", Name = "Button7NotVisible")]
         [TemplatePart(Name = "btn0", Type = typeof(Control))]
         [TemplatePart(Name = "btn7", Type = typeof(Control))]
         [TemplatePart(Name = "btnMore", Type = typeof(Control))]
         [TemplateVisualState(GroupName = "MoreButtonStates", Name = "MoreButtonVisible")]
         [TemplateVisualState(GroupName = "MoreButtonStates", Name = "MoreButtonNotVisible")]
         public class FourByTwoGrid : Control
         {



        public FourByTwoGrid()
        {
            this.DefaultStyleKey = typeof(FourByTwoGrid);

            this.Loaded += new RoutedEventHandler(FourByTwoGrid_Loaded); 
            this.GotFocus += new RoutedEventHandler(FourByTwoGrid_GotFocus);
        }

        public IList ItemsSource
        {
            get {  return GetValue(ItemsSourceProperty) as IList; }
            set { Logger.Log("Value set"); SetValue(ItemsSourceProperty, value); }
        }

        /// <summary>
        /// Identifies the ItemsSource dependency property.
        /// </summary>
        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register(
                "ItemsSource",
                typeof(IList),
                typeof(FourByTwoGrid),
                new PropertyMetadata(null, OnItemsSourcePropertyChanged));

        /// <summary>
        /// ItemsSourceProperty property changed handler.
        /// </summary>
        /// <param name="d">FourByTwoGrid that changed its ItemsSource.</param>
        /// <param name="e">Event arguments.</param>
        private static void OnItemsSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FourByTwoGrid source = d as FourByTwoGrid;          

            if (source != null)
            {
                source.AttemptToBuildGridUi();
            }
        }

   #region public DataTemplate ItemTemplate
        /// <summary>
        /// Gets or sets an ItemTemplate to be used in the buttons. 
        /// </summary>
        public DataTemplate ItemTemplate
        {
            get { return GetValue(ItemTemplateProperty) as DataTemplate; }
            set { SetValue(ItemTemplateProperty, value); }
        }

        /// <summary>
        /// Identifies the ItemTemplate dependency property.
        /// </summary>
        public static readonly DependencyProperty ItemTemplateProperty =
            DependencyProperty.Register(
                "ItemTemplate",
                typeof(DataTemplate),
                typeof(FourByTwoGrid),
                new PropertyMetadata(null, OnItemTemplatePropertyChanged));

        /// <summary>
        /// ItemTemplateProperty property changed handler.
        /// </summary>
        /// <param name="d">FourByTwoGrid that changed its ItemTemplate.</param>
        /// <param name="e">Event arguments.</param>
        private static void OnItemTemplatePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FourByTwoGrid source = d as FourByTwoGrid;

            if (source != null)
            {
                source.AttemptToBuildGridUi();
            }
        }

        /// <summary>
        /// Update the visual state of buttons based on whether or not an item exists. 
        /// </summary>
        private void UpdateVisualState()
        {
            // set buttons to visible if there's a corresponding item
            var lastI = 0;

            if (ItemsSource != null)
            {
                for (int i = 0; i < ItemsSource.Count && i < 8; i++)
                {
                    lastI = i;
                    VisualStateManager.GoToState(this, "Button" + i + "Visible", false);
                    Logger.Log("Visible" + i);
                }
                lastI++;
            }


            // set buttons to nto visible for all buttons that don't have a corresponding item
           for (int i = lastI; i < 8; i++)
            {
            }

            if (ShouldMoreButtonBeVisible)
            {
                VisualStateManager.GoToState(this, "MoreButtonVisible", false);
            }
            else
            {
                VisualStateManager.GoToState(this, "MoreButtonNotVisible", false);
            }
        }

        /// <summary>
        /// Attempt to populate the UI based on control properties. 
        /// </summary>
        private void AttemptToBuildGridUi()
        {
            UpdateVisualState();

            UpdateItemsSourceBindings();
        }

        /// <summary>
        /// It seems that the TemplateParent bindings aren't automatically updated. 
        /// We'll invoke Update on each of these. 
        /// </summary>
        private void UpdateItemsSourceBindings()
        {

            if (ItemsSource == null)
                return;

            if ((ItemsSource.Count > 0) && !ItemsSource[0].Equals(Item0))
                Item0 = ItemsSource[0];

            if ((ItemsSource.Count > 1) && !ItemsSource[1].Equals(Item1))
                Item1 = ItemsSource[1];

            if ((ItemsSource.Count > 2) && !ItemsSource[2].Equals(Item2))
                Item2 = ItemsSource[2];

            if ((ItemsSource.Count > 3) && !ItemsSource[3].Equals(Item3))
                Item3 = ItemsSource[3];

            if ((ItemsSource.Count > 4) && !ItemsSource[4].Equals(Item4))
                Item4 = ItemsSource[4];

            if ((ItemsSource.Count > 5) && !ItemsSource[5].Equals(Item5))
                Item5 = ItemsSource[5];

            if ((ItemsSource.Count > 6) && !ItemsSource[6].Equals(Item6))
                Item6 = ItemsSource[6];

            if ((ItemsSource.Count > 7) && !ItemsSource[7].Equals(Item7))
                Item7 = ItemsSource[7];

            Logger.Log("Layout updated");
            ItemsCountText = ItemsSource.Count.ToString(CultureInfo.InvariantCulture);
        }

#region public object Item0
        /// <summary>
        /// Gets or sets item #0.
        /// </summary>
        public object Item0
        {
            get { return GetValue(Item0Property) as object; }
            set { SetValue(Item0Property, value); }
        }

        /// <summary>
        /// Identifies the Item0 dependency property.
        /// </summary>
        public static readonly DependencyProperty Item0Property =
            DependencyProperty.Register(
                "Item0",
                typeof(object),
                typeof(FourByTwoGrid),
                new PropertyMetadata(null));

        #endregion public object Item0

        #region public object Item1
        /// <summary>
        /// Gets or sets item #1.
        /// </summary>
        public object Item1
        {
            get { return GetValue(Item1Property) as object; }
            set { SetValue(Item1Property, value); }
        }

        /// <summary>
        /// Identifies the Item1 dependency property.
        /// </summary>
        public static readonly DependencyProperty Item1Property =
            DependencyProperty.Register(
                "Item1",
                typeof(object),
                typeof(FourByTwoGrid),
                new PropertyMetadata(null));

        #endregion public object Item1

        #region public object Item2
        /// <summary>
        /// Gets or sets item #2.
        /// </summary>
        public object Item2
        {
            get { return GetValue(Item2Property) as object; }
            set { SetValue(Item2Property, value); }
        }

        /// <summary>
        /// Identifies the Item2 dependency property.
        /// </summary>
        public static readonly DependencyProperty Item2Property =
            DependencyProperty.Register(
                "Item2",
                typeof(object),
                typeof(FourByTwoGrid),
                new PropertyMetadata(null));

        #endregion public object Item2

        #region public object Item3
        /// <summary>
        /// Gets or sets item #3.
        /// </summary>
        public object Item3
        {
            get { return GetValue(Item3Property) as object; }
            set { SetValue(Item3Property, value); }
        }

        /// <summary>
        /// Identifies the Item3 dependency property.
        /// </summary>
        public static readonly DependencyProperty Item3Property =
            DependencyProperty.Register(
                "Item3",
                typeof(object),
                typeof(FourByTwoGrid),
                new PropertyMetadata(null));

        #endregion public object Item3

        #region public object Item4
        /// <summary>
        /// Gets or sets item #4.
        /// </summary>
        public object Item4
        {
            get { return GetValue(Item4Property) as object; }
            set { SetValue(Item4Property, value); }
        }

        /// <summary>
        /// Identifies the Item4 dependency property.
        /// </summary>
        public static readonly DependencyProperty Item4Property =
            DependencyProperty.Register(
                "Item4",
                typeof(object),
                typeof(FourByTwoGrid),
                new PropertyMetadata(null));

        #endregion public object Item4

        #region public object Item5
        /// <summary>
        /// Gets or sets item #5.
        /// </summary>
        public object Item5
        {
            get { return GetValue(Item5Property) as object; }
            set { SetValue(Item5Property, value); }
        }

        /// <summary>
        /// Identifies the Item5 dependency property.
        /// </summary>
        public static readonly DependencyProperty Item5Property =
            DependencyProperty.Register(
                "Item5",
                typeof(object),
                typeof(FourByTwoGrid),
                new PropertyMetadata(null));

        #endregion public object Item5

        #region public object Item6
        /// <summary>
        /// Gets or sets item #6.
        /// </summary>
        public object Item6
        {
            get { return GetValue(Item6Property) as object; }
            set { SetValue(Item6Property, value); }
        }

        /// <summary>
        /// Identifies the Item6 dependency property.
        /// </summary>
        public static readonly DependencyProperty Item6Property =
            DependencyProperty.Register(
                "Item6",
                typeof(object),
                typeof(FourByTwoGrid),
                new PropertyMetadata(null));

        #endregion public object Item6

        #region public object Item7
        /// <summary>
        /// Gets or sets item #7.
        /// </summary>
        public object Item7
        {
            get { return GetValue(Item7Property) as object; }
            set { SetValue(Item7Property, value); }
        }

        /// <summary>
        /// Identifies the Item7 dependency property.
        /// </summary>
        public static readonly DependencyProperty Item7Property =
            DependencyProperty.Register(
                "Item7",
                typeof(object),
                typeof(FourByTwoGrid),
                new PropertyMetadata(null));

        #endregion public object Item7

EpisodeList is an IList in the SeriesViewModel class, I would like to bind that list to my EpisodeGrid control.

public class SeriesViewModel : CoreViewModel
{
     public IList episodeList = new ObservableCollection<Episode>
     {
         new Episode {image =""},

         new Episode {image =""},
         ......
     }


    public IList EpisodeList
    {
        get {return this.episodeList;}
        set
        {
            this.episodeList = value;
            RaisePropertyChanged("EpisodeList");
        }
    }
 }

<Core:CoreView
xmlns:Core="clr-namespace:AmebaTV_XBOXApplication.ViewModel"
x:Class="AmebaTV_XBOXApplication.UI.EpisodeGridView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:GridLayout="clr-namespace:AmebaTV_XBOXApplication.Controls.GridLayout"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:xbox="clr-namespace:Microsoft.Xbox.Controls;assembly=Microsoft.Xbox"
mc:Ignorable="d"
d:DesignHeight="720" d:DesignWidth="1280"
Title="EpisodeGridView Page">

<Core:CoreView.ViewModel>
    <Binding Path="SeriesViewModel" Source="{StaticResource viewModelLocator}"/>
</Core:CoreView.ViewModel>

<Core:CoreView.Resources>
    <DataTemplate x:Key="button_template">
        <Button Width="50" Height="50" >
            <TextBlock Text="Button"/>
        </Button>
    </DataTemplate>
</Core:CoreView.Resources>

  <Grid x:Name="LayoutRoot"  Margin="0">         
    <GridLayout:FourByTwoGrid x:Name="fourbytwogrid"
              ItemsSource="{Binding EpisodeList}"
              ItemTemplate="{StaticResource button_template}"/>

  </Grid>
</Core:CoreView>

What am I missing above? it compiles fine, but at runtime The EpisodeList does not bind.

2
Do you have an EpisodeList property on your viewmodel which wraps the episodeList field?nemesv
@nemesv , yes I do , I'll include it in the editFabii
What do you mean on "EpisodeList does not bind"? How do you use the ItemsSource DP in your EpisodeGrid?nemesv
ItemsSource="{Binding EpisodeList}"Fabii
EpisodeGrid is the custom UserControl, EpisodeList is the list of items for ItemSource.Fabii

2 Answers

1
votes

I have looked at the code and it does appear to bind fine.

If you set a break-point in the OnItemsSourcePropertyChanged method, you can see that the DP ItemsSourceProperty is bound to the EpisodeList and that the call to get IList stored in the property ItemsSource has exactly the value we would expect to have.

What evidence suggests that the EpisodeList is not bound to ItemsSource?

If the problem is that the grid buttons are not displaying, I'm not sure you have shown any code for how you create the button controls, perhaps the issue is there and not in the binding.

Here is an example of a ControlTemplate I have written that manages the state you defined in your FourByTwoGrid class. You can add the following in your XAML to reference it.

    <GridLayout:FourByTwoGrid x:Name="fourbytwogrid"
      ItemsSource="{Binding EpisodeList}"
      ItemTemplate="{StaticResource butemp}"
      Template="{StaticResource FourByTwoGridTemplate}" />

And here is the definition of the ControlTemplate. Without this, your code has no way of knowing how to display the states you reference in your method UpdateVisualState().

Add this to your resource dictionary in your CoreView XAML:

<ControlTemplate x:Key="FourByTwoGridTemplate" TargetType="GridLayout:FourByTwoGrid">
        <Grid>
            <vsm:VisualStateManager.VisualStateGroups>
                <vsm:VisualStateGroup x:Name="Button0States">
                    <vsm:VisualState x:Name="Button0Visible">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Button0">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </vsm:VisualState>
                    <vsm:VisualState x:Name="Button0NotVisible">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Button0">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </vsm:VisualState>
                </vsm:VisualStateGroup>
                <vsm:VisualStateGroup x:Name="Button1States">
                    <vsm:VisualState x:Name="Button1Visible">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Button1">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </vsm:VisualState>
                    <vsm:VisualState x:Name="Button1NotVisible">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Button1">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </vsm:VisualState>
                </vsm:VisualStateGroup>
                <vsm:VisualStateGroup x:Name="Button2States">
                    <vsm:VisualState x:Name="Button2Visible">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Button2">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </vsm:VisualState>
                    <vsm:VisualState x:Name="Button2NotVisible">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Button2">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </vsm:VisualState>
                </vsm:VisualStateGroup>

            </vsm:VisualStateManager.VisualStateGroups>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Button Grid.Row="0" Grid.Column="0" Name="Button0" Content="0" Visibility="Hidden" />
            <Button Grid.Row="0" Grid.Column="1" Name="Button1" Content="1" Visibility="Hidden" />
            <Button Grid.Row="1" Grid.Column="0" Name="Button2" Content="2" Visibility="Hidden" />
            <Button Grid.Row="1" Grid.Column="1" Name="Button3" Content="3" Visibility="Hidden" />
            <Button Grid.Row="2" Grid.Column="0" Name="Button4" Content="4" Visibility="Hidden" />
            <Button Grid.Row="2" Grid.Column="1" Name="Button5" Content="5" Visibility="Hidden" />
            <Button Grid.Row="3" Grid.Column="0" Name="Button6" Content="6" Visibility="Hidden" />
            <Button Grid.Row="3" Grid.Column="1" Name="Button7" Content="7" Visibility="Hidden" />
        </Grid>
</ControlTemplate>

0
votes

It looks like the problem is in the ViewModel. You're attempting to bind ItemsSource to a property named "EpisodeList". But the RaisePropertyChanged refers to the non-bound member "episodeList".