0
votes

So I have a TabControl that has an instance of ViewModel1 as each tab. ViewModel1's View has a custom UserControl I built, that basically exposes a DependencyProperty "Images" that stores the list of images the control has. This property has been bound (OneWayToSource) to ViewModel1's property "Images".

The problem I'm having is that for some reason, all instances of ViewModel1 (all tabs) are sharing this property. So if Tab1 has 1 image in the control, and Tab2 has 3 images in the control, the "Images" property of each ViewModel1 instance has a collection of 4 images.

I don't know how anything like this could happen - anyone have any ideas?

Note that I'm using Caliburn.Micro as a MVVM framework.

EDIT: The property inside the control is defined like this:

public List<ImageData> Images
    {
        get { return (List<ImageData>)GetValue(ImagesProperty); }
        set { return; }
    }

    public static readonly DependencyProperty ImagesProperty =
        DependencyProperty.Register("Images", typeof(List<ImageData>), typeof(WebImageAlbum), 
            new UIPropertyMetadata(new List<ImageData>()));

New items are just added to that with Images.Add() and inside the View's XAML, this property is bound to the ViewModel's "Images" property with Mode=OneWayToSource.

EDIT: This is what the Tab view with the UserControl looks like:

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
xmlns:local="clr-namespace:NET_MD3.Views"
xmlns:cal="http://www.caliburnproject.org" 
xmlns:CustomControls="clr-namespace:NET_MD3.CustomControls" x:Class="NET_MD3.Views.AlbumTabView"
mc:Ignorable="d" 
d:DesignHeight="267.789" d:DesignWidth="473.684">
<Grid>
    <CustomControls:WebImageAlbum x:Name="Album" Margin="10,10,10,50" Width="Auto" Height="Auto" ImageWidthHeight="95"
        cal:Message.Attach="[Event ImageClicked] = [Action ImageClicked($eventArgs)]"
        Images="{Binding Images, Mode=OneWayToSource}"/>
    <Button x:Name="CloseTab" Content="Close tab and delete album" HorizontalAlignment="Left" Margin="10,0,0,10" VerticalAlignment="Bottom" Width="172" Height="30"/>
    <Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="342,243,0,0" VerticalAlignment="Top" Width="75" Click="button_Click"/>
</Grid>

This is what the ViewModel looks like:

public class AlbumTabViewModel : Screen, IAlbumTabItem
{
    #region Constructor

    public AlbumTabViewModel(int id)
    {
        this.TabID = id;
    }

    #endregion

    #region Properties

    /// <summary>
    /// Get the Images loaded in this tab's Album (do not use the setter - it's for the Binding only)
    /// </summary>
    public List<ImageData> Images
    {
        get; set;
    }

    /// <summary>
    /// The Display name of this Screen (Tab)
    /// </summary>
    public override string DisplayName
    {
        get
        {
            return $"Album #{this.TabID}"; 
        }
        set { base.DisplayName = value; }
    }

    /// <summary>
    /// The ID of this tab
    /// </summary>
    public int TabID { get; private set; }

    #endregion

    #region Actions

    /// <summary>
    /// Delete this album tab
    /// </summary>
    public void CloseTab()
    {
        this.TryClose();
    }


    /// <summary>
    /// An image has been clicked within the album
    /// </summary>
    /// <param name="e"></param>
    public void ImageClicked(ImageData e)
    {
        //ttt
    }

    #endregion
}
1
My psychic debugger is saying you have a static list. Without the code that's the best I can do.Cameron MacFarland
There's a lot of code in total (View, ViewModel, Custom Control), so it's hard to tell what should I put up. I've added the declaration of the "Images" dependency property, though, so you can take a look at that (it isn't static).Fabis
Why did you make it a DependencyProperty and not simply bound?Joel Lucsy
@Fabis The code of the ViewModel, code that updates the lists, XAML at leastPellared
I made it a DependencyProperty so I could bind to it through XAML, I don't want to do anything in the codebehind.Fabis

1 Answers

0
votes

Turns out the problem was in the declaration of the DependencyProperty. In the UIPropertyMetadata() that I passed to the static declaration of the property, I made it use a 'new List()' as the default value and turns out that you can't really do that, because it will create that List as a static object, which explains why every instance of the UserControl had the same list. This probably happens because the DependencyProperty itself is static and so when it tries to create that default value, it will be static as well.

I guess the lesson is don't put reference types as default values when declaring a new DependencyProperty, and if you must, set it elsewhere (within the CLR property that accesses the value, or something).