This is a migrated thread and some comments may be shown as answers.

Specifying a binding for Tile.DisplayIndex causes exception

6 Answers 148 Views
TileList
This is a migrated thread and some comments may be shown as answers.
Bjorn Inge
Top achievements
Rank 1
Bjorn Inge asked on 15 Nov 2013, 09:37 AM
Hello Telerik,

I'm trying to specify a binding on a tile's displayindex through a style. For some reason i get an exception stating:

System.ArgumentNullException occurred
  HResult=-2147467261
  Message=Value cannot be null.
Parameter name: property
  Source=PresentationFramework
  ParamName=property
  StackTrace:
       at System.Windows.Setter.CheckValidProperty(DependencyProperty property)
  InnerException: 

This is my style for the tiles:

<!-- Tile Style -->
   
<Style TargetType="{x:Type telerik:Tile}">
        <Setter Property="Background">
<Setter.Value>
                <LinearGradientBrush>
                   <GradientStop Color="{Binding RelativeSource={RelativeSource AncestorType={x:Type telerik:Tile}, Mode=FindAncestor}, Path=Content.Color.StartColor}" Offset="0.0" />
                   <GradientStop Color="{Binding RelativeSource={RelativeSource AncestorType={x:Type telerik:Tile}, Mode=FindAncestor}, Path=Content.Color.EndColor}" Offset="1.0" />
                </LinearGradientBrush>
            </Setter.Value>
       </Setter>
       <Setter Property="TileType" Value="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content.Size, Converter={StaticResource tileTypeConverter}}" />
       <Setter Property="DisplayIndex" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type telerik:Tile}, Mode=FindAncestor}, Path=Content.DisplayIndex, Mode=OneTime}" />
</Style>

Am I doing something obviously wrong?

6 Answers, 1 is accepted

Sort by
0
Maya
Telerik team
answered on 18 Nov 2013, 03:07 PM
Hello Bjorn,

Currently, DisplayIndex property of the tile is not a dependency one and you cannot bind it. That is why you are getting such error. We will consider changing it to dependency property, but for the time being it is just a regular CLR property.   

Regards,
Maya
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
0
Muhammad Ummar
Top achievements
Rank 1
answered on 27 May 2014, 07:44 AM
Hello Maya,

I need to save the DisplayIndex to database so I can set a position of Tile next time it gets loaded. I want to know how can I update the ViewModel's property when DisplayIndex is changed using Drag and Drop operation? I know it is not a dependency property so data binding wouldn't be possible, any other workaround for this problem? 

Regards
Ummar
0
Boris
Telerik team
answered on 30 May 2014, 08:24 AM
Hello Ummar,

We will need a little more time to think of a possible workaround. We will get back to you as soon as possible.

Regards,
Boris Penev
Telerik
 
Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
 
0
Boris
Telerik team
answered on 30 May 2014, 04:51 PM
Hello Ummar,

A possible approach for fulfilling your requirement is to attach a OnDrop() handler to the TileList by using the DragDropManager.AddDropHandler() method. In that handler you will need to get all the Tiles of the TileList by using the  ChildrenOfType<Tile>() extension method. Then get the business object for each tile by using its DataContext property and set DisplayIndex property of your Business object to the DisplayIndex property of the Tile.
In order to load initially in any particular order the tiles, you can use the AutoGeneratingTile event of the TileList.

Please examine the attached a sample project that demonstrates the suggested approach and let us know if this helps.

Regards,
Boris Penev
Telerik
 
Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
 
Joshua
Top achievements
Rank 1
commented on 16 Jul 2021, 12:58 AM

The problem with manually attaching an OnDrop handler is that none of the state is updated yet. You have to post another delegate to the Dispatcher to get out of the callstack and let the state update first.
0
Muhammad Ummar
Top achievements
Rank 1
answered on 05 Jun 2014, 01:15 PM
Hello Boris,

Thanks for your reply and helpful code example, it worked. THANKS.

But my scenario is little bit different as I am also using the Grouping of tiles, the approach you described worked fine in grouping case as well. But the DisplayIndex printed in OnDrop event handler are not as expected, in fact they contain the wrong values. but visually every thing is fine. Just for my understanding I have updated your project with Group functionality, and added 8 more tiles along with 4 your tiles (means total 12 tiles) divided in 3 groups. So the DisplayIndex renage in 0-11. but when I drag/drop any tile the printed DisplayIndex also contains the wrong values even 26 and 27, which is not possible. Following are the code updates so you can test
 
 The Business object is

001./// <summary>
002.    /// A football club.
003.    /// </summary>
004.    public class Club : INotifyPropertyChanged
005.    {
006.        public event PropertyChangedEventHandler PropertyChanged;
007. 
008.        private string name;
009.        private int? displayIndex;
010. 
011.        public int? DisplayIndex
012.        {
013.            get { return this.displayIndex; }
014.            set
015.            {
016.                if (value != this.displayIndex)
017.                {
018.                    this.displayIndex = value;
019.                    this.OnPropertyChanged("DisplayIndex");
020.                }
021.            }
022.        }
023. 
024.        public string Name
025.        {
026.            get { return this.name; }
027.            set
028.            {
029.                if (value != this.name)
030.                {
031.                    this.name = value;
032.                    this.OnPropertyChanged("Name");
033.                }
034.            }
035.        }
036. 
037.        private string _tileGroup;
038. 
039.        public string TileGroup
040.        {
041.            get { return _tileGroup; }
042.            set
043.            {
044.                _tileGroup = value;
045.                OnPropertyChanged("TileGroup");
046.            }
047.        }
048.         
049. 
050.        public Club()
051.        {
052. 
053.        }
054. 
055.        public Club(string name, int displayIndex, string groupHeader)
056.        {
057.            this.name = name;
058.            this.displayIndex = displayIndex;
059.            TileGroup = groupHeader;
060.        }
061. 
062.        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
063.        {
064.            PropertyChangedEventHandler handler = this.PropertyChanged;
065.            if (handler != null)
066.            {
067.                handler(this, args);
068.            }
069.        }
070. 
071.        private void OnPropertyChanged(string propertyName)
072.        {
073.            this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
074.        }
075. 
076.        public override string ToString()
077.        {
078.            return this.Name;
079.        }
080. 
081.        public static ObservableCollection<Club> GetClubs()
082.        {
083.            ObservableCollection<Club> clubs = new ObservableCollection<Club>();
084.            Club club;
085. 
086.            // Liverpool
087.            club = new Club("Liverpool", 3, "Group1");
088.            clubs.Add(club);
089. 
090.            // Manchester Utd.
091.            club = new Club("Manchester Utd.", 2, "Group1");
092.            clubs.Add(club);
093. 
094.            // Chelsea
095.            club = new Club("Chelsea", 0, "Group1");
096.            clubs.Add(club);
097. 
098.            // Arsenal
099.            club = new Club("Arsenal", 1, "Group1");
100.            clubs.Add(club);
101. 
102.            // Liverpool
103.            club = new Club("Liverpool-Group2", 7, "Group2");
104.            clubs.Add(club);
105. 
106.            // Manchester Utd.
107.            club = new Club("Manchester Utd-Group2.", 6, "Group2");
108.            clubs.Add(club);
109. 
110.            // Chelsea
111.            club = new Club("Chelsea-Group2", 4, "Group2");
112.            clubs.Add(club);
113. 
114.            // Arsenal
115.            club = new Club("Arsenal-Group2", 5, "Group2");
116.            clubs.Add(club);
117. 
118.            // Liverpool
119.            club = new Club("Liverpool-Group3", 11, "Group3");
120.            clubs.Add(club);
121. 
122.            // Manchester Utd.
123.            club = new Club("Manchester Utd-Group3.", 10, "Group3");
124.            clubs.Add(club);
125. 
126.            // Chelsea
127.            club = new Club("Chelsea-Group3", 8, "Group3");
128.            clubs.Add(club);
129. 
130.            // Arsenal
131.            club = new Club("Arsenal-Group3", 9, "Group3");
132.            clubs.Add(club);
133. 
134.            return clubs;
135.        }
136.    }


The updated Main window code is 
01.<Window x:Class="RadTileList_WPF_DisplayIndex.MainWindow"
04.        xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
05.        xmlns:my="clr-namespace:RadTileList_WPF_DisplayIndex"
06.        Title="MainWindow" Height="700" Width="700">
07.    <Window.Resources>
08.        <my:MyViewModel x:Key="MyViewModel"/>
09.    </Window.Resources>
10.    <Grid DataContext="{StaticResource MyViewModel}">
11.        <Grid.RowDefinitions>
12.            <RowDefinition Height="*"/>
13.            <RowDefinition Height="Auto" />
14.        </Grid.RowDefinitions>
15.        <telerik:RadTileList x:Name="tileList"
16.                             ItemsSource="{Binding Clubs}"
17.                             AutoGeneratingTile="tileList_AutoGeneratingTile"
18.                             ScrollViewer.HorizontalScrollBarVisibility="Visible">
19.            <telerik:RadTileList.GroupTemplate>
20.                <DataTemplate>
21.                    <TextBlock Margin="0,0,0,10" Text="{Binding}" FontSize="16"></TextBlock>
22.                </DataTemplate>
23.            </telerik:RadTileList.GroupTemplate>
24.            </telerik:RadTileList>
25.    </Grid>
26.</Window>

and finally the code behind for Main window is 

01.using System;
02.using System.Collections.Generic;
03.using System.Linq;
04.using System.Text;
05.using System.Windows;
06.using System.Windows.Controls;
07.using System.Windows.Data;
08.using System.Windows.Documents;
09.using System.Windows.Input;
10.using System.Windows.Media;
11.using System.Windows.Media.Imaging;
12.using System.Windows.Navigation;
13.using System.Windows.Shapes;
14.using Telerik.Windows.Controls;
15.using System.Diagnostics;
16.using Telerik.Windows.DragDrop;
17. 
18.namespace RadTileList_WPF_DisplayIndex
19.{
20.    /// <summary>
21.    /// Interaction logic for MainWindow.xaml
22.    /// </summary>
23.    public partial class MainWindow : Window
24.    {
25.        public MainWindow()
26.        {
27.            InitializeComponent();
28.            DragDropManager.AddDropHandler(this.tileList, OnDrop);
29.        }
30. 
31.        private void OnDrop(object sender, Telerik.Windows.DragDrop.DragEventArgs e)
32.        {
33.            e.Handled = true;
34.            var tiles = this.tileList.ChildrenOfType<Tile>();
35.            foreach (Tile tile in tiles)
36.            {
37.                Club club = tile.DataContext as Club;
38.                club.DisplayIndex = tile.DisplayIndex;
39.                Debug.WriteLine("Name: " + club.Name + "; DisplayIndex: " + club.DisplayIndex);
40.            }
41.        }
42. 
43.        private void tileList_AutoGeneratingTile(object sender, AutoGeneratingTileEventArgs e)
44.        {
45.            e.Tile.DisplayIndex = (e.Tile.DataContext as Club).DisplayIndex;
46.            e.Tile.Group = (e.Tile.DataContext as Club).TileGroup;
47.        }
48.    }
49.}

Run the code and Drag any tile and Drop it to some other group, on the debug console you will see the wrong entries of DisplayIndex. and each time you drag tiles you will see DisplayIndex increasing.

Just a reminder that visually every thing works fine and on next reload the tiles appear in correct position. but I am wondering about wrong values of DisplayIndex? Could you please clarify?
0
Boris
Telerik team
answered on 09 Jun 2014, 12:57 PM
Hello Ummar,

Thank you for reporting this issue. We reviewed the TileList control and we can confirm that the reported behavior is actually a bug. We logged it in our feedback portal where you can track its status. We also updated your Telerik account points as a thanks for your cooperation in reporting this issue.

Regards,
Boris Penev
Telerik
 
Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
 
Tags
TileList
Asked by
Bjorn Inge
Top achievements
Rank 1
Answers by
Maya
Telerik team
Muhammad Ummar
Top achievements
Rank 1
Boris
Telerik team
Share this question
or