我有两个ObservableCollection
个Screenshot
个对象。一个称为Screenshots
,其中包含用户可用的所有可能屏幕,一个称为SelectedScreenshots
,这是用户想要组合的所选屏幕。每次用户通过点击在WPF中绑定到SelectedScreenshots
Screenshots
中添加一个新屏幕
问题在于,当我刷新屏幕并清除Screenshots
以便我看到屏幕上已更新的内容时,即使它是另一个对象,它也会清除SelectedScreenshots
。我确实理解他们指向内存中的相同位置,但我该如何解决呢?深度复制是一种解决方案。还有其他选择吗?
属性:
public ObservableCollection<Screenshot> Screenshots { get; set; } = new ObservableCollection<Screenshot>();
public ObservableCollection<Screenshot> SelectedScreenshots { get; set; } = new ObservableCollection<Screenshot>();
在此处初始化和刷新屏幕:
private void InitScreens()
{
var screenshots = Screen.AllScreens.OrderBy(scrn => scrn.Bounds.Location.X).ThenBy(scrn => scrn.Bounds.Location.Y).Select(screen => new Screenshot(GetScreenImage(screen.Bounds), screen.DeviceName));
App.Current.Dispatcher.InvokeAsync(delegate
{
Screenshots.Clear();
for (int i = 0; i < 3; i++)
{
Screenshots.Add(screenshots.ElementAt(i));
}
});
}
添加和删除SelectedScreenshots
:
private void lst_ScreenShots_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (Screenshot item in e.RemovedItems)
{
vm.SelectedScreenshots.Remove(item);
}
foreach (Screenshot item in e.AddedItems)
{
vm.SelectedScreenshots.Add(item);
}
}
屏幕截图类:
public class Screenshot : ViewModelBase
{
private BitmapImage _screenImage;
public BitmapImage ScreenImage
{
get { return _screenImage; }
set
{
_screenImage = value;
OnPropertyChanged();
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
public Screenshot(BitmapImage screenImage, string name)
{
this.ScreenImage = screenImage;
this.Name = name;
}
}
答案 0 :(得分:2)
正在清除SelectedScreenshots的UI,因为您绑定的控件只能包含项目源中存在的所选项目,并且每次刷新时都会创建一组全新的屏幕截图。
解决方案是在刷新之前将所选项目保存到另一个集合,然后重新选择或仅更新现有的屏幕截图集。
我希望您能够在UI中保留所选的屏幕截图。为了实现这一点,您需要以某种方式将旧屏幕截图实例链接到新屏幕截图实例。希望你能用DeviceName做到这一点?还是按顺序?将这一点留给你。
private void InitScreens()
{
var screenshots = Screen.AllScreens.OrderBy(scrn => scrn.Bounds.Location.X).ThenBy(scrn => scrn.Bounds.Location.Y).Select(screen => new Screenshot(GetScreenImage(screen.Bounds), screen.DeviceName));
App.Current.Dispatcher.InvokeAsync(delegate
{
// store current selections
var currentSelections = SelectedScreenshots.ToArray();
Screenshots.Clear();
for (int i = 0; i < 3; i++)
{
Screenshots.Add(screenshots.ElementAt(i));
}
// select what was previously selected
SelectedScreenshots = new ObservableCollection<Screenshot>(Screenshots
.Where(s => currentSelections.Any(c => c.DeviceName == s.DeviceName)));
});
}
答案 1 :(得分:1)
如果您的屏幕截图对象具有引用类型的属性,那么我认为您需要按照您的说法进行操作;执行深层复制以确保Screenshots属性中的Screenshot对象和SelectedScreenshots属性中的Screenshot对象不指向相同的内存位置。在过去,我在对象中创建了一个PerformDeepCopy()方法,在您的情况下是Screenshot对象。在此方法中,您可以执行MemberwiseClone(),这是一个浅表副本。这将复制Screenshot类中的Name属性。然后,您将手动为引用类型分配新的内存地址。这是BitmapImage属性“newed up”的地方。返回值是一个新的Screenshot对象。例如:
public class Screenshot : ViewModelBase
{
private BitmapImage _screenImage;
public BitmapImage ScreenImage
{
get { return _screenImage; }
set
{
_screenImage = value;
OnPropertyChanged();
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
public Screenshot(BitmapImage screenImage, string name)
{
this.ScreenImage = screenImage;
this.Name = name;
}
public Screenshot PerformDeepCopy()
{
Screenshot deepCopy = (Screenshot)this.MemberwiseClone();
deepCopy.ScreenImage = new BitmapImage(this.ScreenImage.UriSource);
return deepCopy;
}
}