Search code examples
c#silverlightbindinguielementinvocationtargetexception

Silverlight: TargetInvocationException Occurred by Bind UIElement To ListBoxItems


I create a ListBox and bind ItemsSource to list of object:

MainPage.xaml:

<Grid x:Name="LayoutRoot" Background="White"
         DataContext="{StaticResource ResourceKey=ViewModel}">

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="47*"/>
            <ColumnDefinition Width="28*"/>
        </Grid.ColumnDefinitions>

        <ListBox ItemsSource="{Binding Models}"
                     Height="200" Width="150"  Grid.Column="0">
            <ListBox.ItemTemplate>
                <DataTemplate >
                    <StackPanel>
                        <TextBlock Text="{Binding ID ,Mode=TwoWay 
                              ,UpdateSourceTrigger=PropertyChanged}"/>
                        <TextBlock Text="{Binding Name ,Mode=TwoWay 
                              ,UpdateSourceTrigger=PropertyChanged}"/>
                        <Border Child="{Binding Shape ,Mode=TwoWay 
                              ,UpdateSourceTrigger=PropertyChanged}"/>

                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

        <Button Content="Change Source" Height="35" Width="100" 
                Grid.Column="1">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <i:InvokeCommandAction Command="{Binding  ChangeSource}"  
                    CommandParameter="{Binding ElementName=LayoutRoot}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>

    </Grid>

Model.cs:

public class Model
{
    private string _ID;
    private UIElement _Shape;
    private string _Name;

    public string Name
    {
        get { return _Name; }
        set { _Name = value; }
    }

    public UIElement Shape
    {
        get { return _Shape; }
        set { _Shape = value;}
    }

    public string ID
    {
        get { return _ID; }
        set { _ID = value; }
    }
}

And

ViewModel.cs:

    public class ViewModel : INotifyPropertyChanged
    {
        Random rnd = new Random();
        List<Color> MyColors = new List<Color>() { Colors.Gray,
                               Colors.Blue, Colors.Red,
                               Colors.Green, Colors.Yellow, 
                               Colors.Orange, Colors.DarkGray };

        private List<Model> _Models;

        public List<Model> Models
        {
            get 
            {
                if (_Models == null)
                    _Models = new List<Model>();
                return _Models;
            }
            set { _Models = value; OnPropertyChanged("Models"); }
        }

        public DelegateCommand<object> ChangeSource { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string PropertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
        }


        public ViewModel()
        {
            ChangeSource = new DelegateCommand<object>(ChangeSourceCommand);

            ChangeSourceItems();
        }

        private void ChangeSourceCommand(object obj)
        {
            ChangeSourceItems();
        }
        private void ChangeSourceItems()
        {
            List<Model> tmpModels = new List<Model>();

            tmpModels.Add(new Model() { ID = "1", Name = "A", Shape = new Border() { Background = new SolidColorBrush(MyColors[rnd.Next(0, MyColors.Count - 1)]), Width = 10, Height = 10 } });
            tmpModels.Add(new Model() { ID = "2", Name = "B", Shape = new Border() { Background = new SolidColorBrush(MyColors[rnd.Next(0, MyColors.Count - 1)]), Width = 10, Height = 10 } });
            tmpModels.Add(new Model() { ID = "3", Name = "C", Shape = new Border() { Background = new SolidColorBrush(MyColors[rnd.Next(0, MyColors.Count - 1)]), Width = 10, Height = 10 } });
            tmpModels.Add(new Model() { ID = "4", Name = "D", Shape = new Border() { Background = new SolidColorBrush(MyColors[rnd.Next(0, MyColors.Count - 1)]), Width = 10, Height = 10 } });
            tmpModels.Add(new Model() { ID = "5", Name = "E", Shape = new Border() { Background = new SolidColorBrush(MyColors[rnd.Next(0, MyColors.Count - 1)]), Width = 10, Height = 10 } });
            tmpModels.Add(new Model() { ID = "6", Name = "F", Shape = new Border() { Background = new SolidColorBrush(MyColors[rnd.Next(0, MyColors.Count - 1)]), Width = 10, Height = 10 } });

            Models = tmpModels;
        }
    }

Source of Models changed with click on Button.

Question:

TargetInvocationException occurred after click on Button and scroll ListView. Why?

Exception Message:

Exception has been thrown by the target of an invocation.

InnerException Message:

Value does not fall within the expected range.


Solution

  • Because you are using UIElement in model, shape created more than once and with scrolling occurred TargetInvocationException.

    You must be inherit ListBox and override IsItemItsOwnContainerOverride method.

    protected override bool IsItemItsOwnContainerOverride(object item)
    {
         Model model = (Model)item;
    
         FrameworkElement elem = (FrameworkElement)model.Shape;
    
         return elem.Parent != null;
    }