WPF MVVM-由于某种原因在ViewModels之间共享的集合

WPF MVVM-由于某种原因在ViewModels之间共享的集合,wpf,mvvm,caliburn.micro,Wpf,Mvvm,Caliburn.micro,所以我有一个TabControl,每个tab都有一个ViewModel1实例。ViewModel1的视图有一个我构建的自定义UserControl,它基本上公开了一个DependencyProperty“Images”,该属性存储控件所具有的图像列表。此属性已绑定(OneWayToSource)到ViewModel1的属性“Images” 我遇到的问题是,出于某种原因,ViewModel1的所有实例(所有选项卡)都共享此属性。因此,如果Tab1在控件中有1个图像,而Tab2在控件中有3个图像,则

所以我有一个TabControl,每个tab都有一个ViewModel1实例。ViewModel1的视图有一个我构建的自定义UserControl,它基本上公开了一个DependencyProperty“Images”,该属性存储控件所具有的图像列表。此属性已绑定(OneWayToSource)到ViewModel1的属性“Images”

我遇到的问题是,出于某种原因,ViewModel1的所有实例(所有选项卡)都共享此属性。因此,如果Tab1在控件中有1个图像,而Tab2在控件中有3个图像,则每个ViewModel1实例的“images”属性都有4个图像的集合

我不知道这样的事情怎么会发生——有人有什么想法吗

注意,我使用Caliburn.Micro作为MVVM框架

编辑:控件内的属性定义如下:

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>()));
公共列表图像
{
获取{return(List)GetValue(ImagesProperty);}
集合{return;}
}
公共静态只读从属属性ImagesProperty=
DependencyProperty.Register(“图像”)、typeof(列表)、typeof(WebImageAlbum),
新的UIPropertyMetadata(新列表());
在视图的XAML中,这个属性被绑定到ViewModel的“Images”属性,Mode=OneWayToSource

编辑:这是带有UserControl的选项卡视图的外观:

<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>
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
}

这就是ViewModel的外观:

<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>
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
}
公共类AlbumTabViewModel:屏幕,IAlbumTabItem
{
#区域构造函数
公共相册tabviewmodel(int-id)
{
this.TabID=id;
}
#端区
#区域属性
/// 
///获取加载到此选项卡的相册中的图像(不要使用setter-它仅用于绑定)
/// 
公共列表图像
{
获得;设置;
}
/// 
///此屏幕的显示名称(选项卡)
/// 
公共重写字符串DisplayName
{
得到
{
返回$“相册#{this.TabID}”;
}
设置{base.DisplayName=value;}
}
/// 
///此选项卡的ID
/// 
public int TabID{get;private set;}
#端区
#区域行动
/// 
///删除此相册选项卡
/// 
public void CloseTab()
{
this.TryClose();
}
/// 
///已在相册中单击图像
/// 
/// 
已单击公共无效图像(图像数据e)
{
//ttt
}
#端区
}

原来问题出在DependencyProperty的声明中。在我传递给属性的静态声明的UIPropertyMetadata()中,我让它使用“new List()”作为默认值,结果证明您不能这样做,因为它将创建作为静态对象的列表,这解释了为什么UserControl的每个实例都有相同的列表。这可能是因为DependencyProperty本身是静态的,因此当它尝试创建默认值时,它也将是静态的


我想教训是,在声明新的DependencyProperty时不要将引用类型作为默认值,如果必须,请在其他位置(在访问该值的CLR属性内)设置它。

我的心理调试器说您有一个静态列表。没有代码,这是我能做的最好的了。总共有很多代码(视图、视图模型、自定义控件),所以很难说我应该放什么。不过,我已经添加了“Images”依赖属性的声明,所以您可以查看一下(它不是静态的)。为什么要将其设置为DependencyProperty而不是简单地绑定?@Fabis是ViewModel的代码,更新列表的代码,至少XAML将其设置为DependencyProperty,以便我可以通过XAML绑定到它,我不想在暗箱操作中做任何事情。