可观察的集合深拷贝

时间:2015-09-07 13:23:29

标签: c# wpf

我在这个应用程序中有一个统一的网格。调整窗口大小后(宽度<300时),它会从网格中删除右列,并更改IsEnabled=false个项目。恢复到之前的大小(宽度> 300)后,它会添加已删除的列及其元素。但似乎没有用。恢复元素后仍然IsEnabled=false为什么?

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public Cars cars;
        public MainWindow()
        {
            cars = new Cars();
            InitializeComponent();
            DataContext = cars;
        }

        public ObservableCollection<CarType> temp;

        public bool Crutch;
        private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (e.NewSize.Width<300)
            {
                if (cars.Items.Count == 4)
                {
                    cars.Columns = 1;
                    cars.Rows = 2;
                    temp = new ObservableCollection<CarType>(from x in cars.Items select (CarType)x.Clone());           
                    cars.Items.ToList().GetRange(2, 2).ForEach(x => x.IsEnabled = false);
                    Crutch = true;
                }
            }
            if (e.NewSize.Width>300)
            {
                if (Crutch)
                {
                    cars.Items = temp;
                    cars.Columns = 2;
                    cars.Rows = 2;
                    Crutch = false;
                }
            }
        }
    }
    public class CarType:ICloneable,INotifyPropertyChanged
    {
        public int number { get; set; }
        public DateTime date { get; set; }
        public string comments { get; set; }

        public bool isEnabled;
        public bool IsEnabled 
        {
            get
            {
                return this.isEnabled;
            }

            set
            {
                this.isEnabled = value;
                RaisePropertyChaged("IsEnabled");
            }
        }
        public CarType()
        {
            IsEnabled = true;
        }
        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChaged(string info)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(info));
        }

        public object Clone()
        {
            return new CarType { number=this.number,IsEnabled=this.IsEnabled,date=this.date,comments=this.comments};
        }
    }
    public class Cars:INotifyPropertyChanged
    {
        private int rows;

        private int columns;
        public int Rows 
        { 
            get
            {
                return this.rows;
            }

            set
            {
                this.rows = value;
                RaisePropertyChaged("Rows");
            }
        }
        public int Columns
        {
            get
            {
                return this.columns;
            }

            set
            {
                this.columns = value;
                RaisePropertyChaged("Columns");
            }
        }

        private ObservableCollection<CarType> items;
        public ObservableCollection<CarType> Items
        {
            get
            {
                return this.items;
            }

            set
            {
                this.items = value;
                RaisePropertyChaged("Items");
            }
        }
        public Cars()
        {
            Rows = 2;
            Columns = 2;
            Items = new ObservableCollection<CarType>();
            Items.Add(new CarType { comments = "First", date  =DateTime.Now, number = 1 });
            Items.Add(new CarType { comments = "First", date = DateTime.Now, number = 2 });
            Items.Add(new CarType { comments = "First", date = DateTime.Now, number = 3 });
            Items.Add(new CarType { comments = "First", date = DateTime.Now, number = 4 });
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChaged(string info)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

XAML

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="250" Width="500" SizeChanged="Window_SizeChanged">
<Canvas>
    <ItemsControl ItemsSource="{Binding Items}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid Columns="{Binding Columns}" Rows="{Binding Rows}"></UniformGrid>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Border BorderBrush="Bisque" BorderThickness="1">
                <Grid Width="200" Height="100" IsEnabled="{Binding IsEnabled}">
                    <Grid.RowDefinitions>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <Label Grid.Row="0" Content="{Binding number}"></Label>
                    <Label Grid.Row="1" Content="{Binding date}"></Label>
                    <Label Grid.Row="2" Content="{Binding comments}"></Label>
                </Grid>
                </Border>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Canvas>

1 个答案:

答案 0 :(得分:2)

每当您调整窗口大小时,窗口的SizeChanged事件会重复 >,当您的大小“完成”时(当您停止调整窗口大小时),您可能只会触发一次),但这是不正确的。

因此,当您将窗口从300变窄到宽于300时,会反复调用此行。

temp = new ObservableCollection<CarType>(from x in cars.Items select (CarType)x.Clone()); 

因此,您正在使用IsEnabled = False制作CarTypes的深层副本。

并在评论中回答您的问题“如何制作正确的副本”:

您可以制作原始副本,然后在需要重新启用网格时使用原始副本的副本。

ObservableCollection<CarType> originalCopy;
public MainWindow()
{
    cars = new Cars();
    originalCopy = new ObservableCollection<CarType>(from x in cars.Items select (CarType)x.Clone());
    ....
}

当您需要此副本的原始副本时:

if (e.NewSize.Width>300)
{
    if (Crutch)
    {
        cars.Items = new ObservableCollection<CarType>(from x in originalCopy select (CarType)x.Clone());

通过这种方式,您的原始副本完好无损(其IsEnbled属性始终为True)。

<强>可是...

我建议您不要使用“复制”,只使用一个ItemSource(cars.Items),并相应地更改IsEnabled属性。复制项目然后重新绑定以后没有多大意义。

我的意思是(为了更好的解释,删除了其他代码)

if (e.NewSize.Width < 300)
{
    cars.Items.ToList().GetRange(2, 2).ForEach(x => x.IsEnabled = false);
}
else //e.NewSize.Width >= 300
{
    cars.Items.ToList().GetRange(2, 2).ForEach(x => x.IsEnabled = true);
}