将 ObservableCollection 彼此分开
Separate ObservableCollections from each other
信息
我有两个 ObservableCollection
相同的 Screenshot
对象。一种称为 Screenshots
,它包含用户可用的所有可能屏幕,一种称为 SelectedScreenshots
,它是用户想要组合的选定屏幕。每次用户通过单击在 WPF 中绑定到 Screenshots
的列表来选择屏幕时,我都会在 SelectedScreenshots
中添加一个新屏幕
问题
问题是,当我刷新屏幕并清除 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);
}
}
截图class:
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;
}
}
正在清除 SelectedScreenshots 的是 UI,因为您绑定到的控件只能包含项目源中存在的 selected 项目,并且在每次刷新时您正在创建一组全新的屏幕截图。
解决方案是在刷新之前将 selected 项目保存到另一个集合并在刷新之后重新select,或者只更新现有的一组屏幕截图。
我预计您会希望在 UI 中保留 selected 的屏幕截图。为了实现这一点,您需要以某种方式 link 旧的屏幕截图实例到新的。希望您可以使用 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)));
});
}
如果您的 Screenshot 对象具有引用类型的属性,那么我认为您需要按照您说的去做;执行深拷贝以确保 Screenshots 属性 中的 Screenshot 对象和 SelectedScreenshots 属性 中的 Screenshot 对象不指向相同的内存位置。过去,我在对象中创建了一个 PerformDeepCopy() 方法,在您的例子中是 Screenshot 对象。在此方法中,您可以执行 MemberwiseClone(),这是一个浅拷贝。这将在您的屏幕截图 class 中复制名称 属性。然后您将手动为引用类型分配一个新的内存地址。这是 BitmapImage 属性 是 "newed up" 的地方。 return 值是一个新的 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;
}
}
信息
我有两个 ObservableCollection
相同的 Screenshot
对象。一种称为 Screenshots
,它包含用户可用的所有可能屏幕,一种称为 SelectedScreenshots
,它是用户想要组合的选定屏幕。每次用户通过单击在 WPF 中绑定到 Screenshots
SelectedScreenshots
中添加一个新屏幕
问题
问题是,当我刷新屏幕并清除 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);
}
}
截图class:
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;
}
}
正在清除 SelectedScreenshots 的是 UI,因为您绑定到的控件只能包含项目源中存在的 selected 项目,并且在每次刷新时您正在创建一组全新的屏幕截图。
解决方案是在刷新之前将 selected 项目保存到另一个集合并在刷新之后重新select,或者只更新现有的一组屏幕截图。
我预计您会希望在 UI 中保留 selected 的屏幕截图。为了实现这一点,您需要以某种方式 link 旧的屏幕截图实例到新的。希望您可以使用 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)));
});
}
如果您的 Screenshot 对象具有引用类型的属性,那么我认为您需要按照您说的去做;执行深拷贝以确保 Screenshots 属性 中的 Screenshot 对象和 SelectedScreenshots 属性 中的 Screenshot 对象不指向相同的内存位置。过去,我在对象中创建了一个 PerformDeepCopy() 方法,在您的例子中是 Screenshot 对象。在此方法中,您可以执行 MemberwiseClone(),这是一个浅拷贝。这将在您的屏幕截图 class 中复制名称 属性。然后您将手动为引用类型分配一个新的内存地址。这是 BitmapImage 属性 是 "newed up" 的地方。 return 值是一个新的 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;
}
}