WPF MVVM-由于某种原因在ViewModels之间共享的集合
所以我有一个TabControl,每个tab都有一个ViewModel1实例。ViewModel1的视图有一个我构建的自定义UserControl,它基本上公开了一个DependencyProperty“Images”,该属性存储控件所具有的图像列表。此属性已绑定(OneWayToSource)到ViewModel1的属性“Images” 我遇到的问题是,出于某种原因,ViewModel1的所有实例(所有选项卡)都共享此属性。因此,如果Tab1在控件中有1个图像,而Tab2在控件中有3个图像,则每个ViewModel1实例的“images”属性都有4个图像的集合 我不知道这样的事情怎么会发生——有人有什么想法吗 注意,我使用Caliburn.Micro作为MVVM框架 编辑:控件内的属性定义如下: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个图像,则
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绑定到它,我不想在暗箱操作中做任何事情。