Domanda

Overview

I have an application, that displays data from an observable collection. The observable collection is (in this debugging setting) created and instanciated only once, then the values stay the same.

The main view of the application contains a ListBox that is bound to said observable collection:

<ListBox x:Name="MainListBox" ItemsSource="{Binding Items}" SelectionChanged="MainListBox_SelectionChanged" >
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel MinWidth="456" MaxWidth="456" Background="White" Margin="0,0,0,17">
                <sparklrControls:SparklrText Post="{Binding Path=.}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
    <!-- Workaround used to stretch the child elements to the full width -> HorizontalContentAlignment won't work for some reason... -->
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

The child items are bound to a UserControl. This UserControl implements a DependancyProperty which the child elements are bound to:

public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(object), new PropertyMetadata(textPropertyChanged));

private static void postPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    SparklrText control = d as SparklrText;
    control.Post = (ItemViewModel)e.NewValue;
}

Binding to the post property configures other variables via the getter of the Post property

    public ItemViewModel Post
    {
        get
        {
            return post;
        }
        set
        {
            if (post != value)
            {
                this.ImageLocation = value.ImageUrl;
                this.Username = value.From;
                this.Comments = value.CommentCount;
                this.Likes = value.LikesCount;
                this.Text = value.Message;

                post = value;
            }
        }
    }

This setter configures other which in turn set up elements in the user control. Nothing in the user control is bound, the few updates are done with direct access to the respective Content/Text properties. ImageLocation performs an asynchronous download of an image with

    private void loadImage(string value)
    {
        WebClient wc = new WebClient();
        wc.OpenReadCompleted += (sender, e) =>
        {
            image = new BitmapImage();
            image.SetSource(e.Result);
            MessageImage.Source = image;
        };

        wc.OpenReadAsync(new Uri(value));
    }

Issue

When I scroll down in the list box and back up, the setter of Post is executed when the owning element comes back into view. The problem: value is a different instance of ItemViewModel. The ListBox ItemsSource is not accessed in any way from outside the class. When scrolling back up, it seems like the wrong Items are bound to the elements, resulting in distorted designs. Are there any issues with the Binding that cause this?

È stato utile?

Soluzione

The issue was caused by the ListBox. Elements that are scroll out of view are recycled and appended on the other side. In the code above, a asynchronous operation did not check if the result was still valid, causing wrong display data.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top