【问题标题】:Saving and storing the contents of a Panel dynamically动态保存和存储面板的内容
【发布时间】:2014-05-03 12:32:02
【问题描述】:

我有一个程序,用户可以在其中创建文本框,并将图像拖放到 Windows 窗体中的面板中,在这里用户可以移动图像、调整大小、删除它们等。基本上是一个非常简单的图像编辑。

我想做的是让这个工作像一个非常简单的 PowerPoint 程序一样。

我正在尝试确定用户是否可以保存具有这些图像(在图片框中)和文本框的面板的内容。然后清除面板并使用新的图像和文本重新开始,但如果他们愿意,可以返回上一个面板并对其进行编辑。

所以程序中的每个面板基本上都是 PowerPoint 中的幻灯片。

目前我可以将面板保存为 Jpeg 并存储这些,但这样我无法重新加载面板并像面板一样编辑内容。

我希望我已经在可以理解的程度上解释了这种情况。

是否可以做我正在尝试的事情,或者我应该以不同的方式解决问题?

【问题讨论】:

    标签: c# winforms image user-interface visual-studio-2012


    【解决方案1】:

    我要解决的方法是定义一个类来存储构成幻灯片的所有信息(因此,可以在代码中表示幻灯片),然后序列化幻灯片列表,称为 Presentation , 作为 XML 文件。

    每张幻灯片都有可变数量的控件,可以是图像、文本框等,所以让我们先定义一个控件:

    public class MySlideClass
    {
        public class Control
        {
            public Point Position       { get; set; }
            public Size  Size           { get; set; }
            public Color Background     { get; set; }
            public Color Forground      { get; set; }
            public Image Picture        { get; set; }
            public string Text          { get; set; }
            public float TextSize       { get; set; }
            public Point TextPosition   { get; set; }
            // ...
            public float Transparency   { get; set; }
            public bool  Visible        { get; set; }
    
            public Control()
            {
            }
        }
    
        public class Slide
        {
            [XmlAttribute]
            public string Name          { get; set; }
            //
            public string Title         { get; set; }
            public Size Size            { get; set; }
            public Color Background     { get; set; }
            public Color Forground      { get; set; }
            public float Transparency   { get; set; }
            public bool Visible         { get; set; }
    
            public List<Control> Children { get; set; }
    
            public Slide()
            {
            }
        }
    
    
        public MySlideClass()
        {
        }
    }
    

    显然,您可以根据需要添加/删除属性。

    注意{ get; set; } 和空的默认构造函数。您的类必须包含公共属性(使用 get/set 定义的变量)并具有一个空的默认构造函数,以便 XMLSerializer 能够序列化您的类(您仍然可以指定其他非空的构造函数)。

    你会像这样使用这些类:

    public void SaveSlideTest()
    {
        // New control
        MySlideClass.Control newControl = new MySlideClass.Control();
        newControl.Position = new Point(20,30);
        newControl.Size     = new Size(75,25);
        newControl.Text     = "Image1";
        newControl.TextPosition= new Point(0,25);
        //ctl.Picture       = new Bitmap("image1.bmp");
    
        // Add control to children list
        List<MySlideClass.Control> childrenControls = new List<MySlideClass.Control>();
        childrenControls.Add(newControl);
    
        // New slide
        MySlideClass.Slide newSlide = new MySlideClass.Slide();
        newSlide.Name   = "Slide1";
        newSlide.Title  = "New Slide";
        newSlide.Size   = new Size(200,100);
        // Add child controls to slide
        newSlide.Children = childrenControls;
    
        // Add slide to presentation or 'slideshow'
        List<MySlideClass.Slide> mySlidePresentation = new List<MySlideClass.Slide>();
        mySlidePresentation.Add( newSlide );
    
        // Save presentation to XML
        SerializeObject("SavedSlidePresentation.xml",mySlidePresentation);
    }
    

    您的 SavedSlidePresentation.xml 如下所示:

    <?xml version="1.0" encoding="utf-8"?>
    <ArrayOfSlide xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <Slide Name="Slide1">
        <Title>New Slide</Title>
        <Size>
          <Width>200</Width>
          <Height>100</Height>
        </Size>
        <Background />
        <Forground />
        <Transparency>0</Transparency>
        <Visible>false</Visible>
        <Children>
          <Control>
            <Position>
              <X>20</X>
              <Y>30</Y>
            </Position>
            <Size>
              <Width>75</Width>
              <Height>25</Height>
            </Size>
            <Background />
            <Forground />
            <Text>Image1</Text>
            <TextSize>0</TextSize>
            <TextPosition>
              <X>0</X>
              <Y>25</Y>
            </TextPosition>
            <Transparency>0</Transparency>
            <Visible>false</Visible>
          </Control>
        </Children>
      </Slide>
    </ArrayOfSlide>
    

    这里是序列化/反序列化函数:

    public static List<MySlideClass.Slide> DeserializePresentation(string FileName)
    {
        List<MySlideClass.Slide> returnList = new List<MySlideClass.Slide>();
    
        using(StreamReader streamReader = new StreamReader(FileName))
        {
            XmlSerializer xmlReader = new XmlSerializer(typeof(List<MySlideClass.Slide>));
            returnList = (List<MySlideClass.Slide>) xmlReader.Deserialize(streamReader);
        }
        return returnList;
    }
    
    // A generic object serializer
    public static void SerializeObject(string Filename,object Obj)
    {
        using(StreamWriter streamWriter = new StreamWriter(Filename))
        {
            XmlSerializer xmlSerializer = new XmlSerializer(Obj.GetType());
            xmlSerializer.Serialize(streamWriter,Obj);
        }
    }
    

    这应该比Dictionary&lt;TKey,TValue&gt; 更健壮。

    需要注意的一个重要方面: 如果您决定向 Slide 或 Control 类添加属性,则反序列化程序将无法使用旧版本的数据类反序列化 XML 文件。

    在这种情况下,您可以 1) 手动或以其他方式转换旧版本的 XML 文件,或者 2) 在您的类中实现 ISerializable 接口(推荐)。

    【讨论】:

    • 您好,感谢您的回复。如何记录控件的类型,例如文本框或图片框?
    • @kev3kev3,最简单的方法是创建一个类似于MySlideClass.Control 的新类,将其命名为 TextboxControl 并对其进行修改以包含您需要的变量。如果您尝试从“控制”类创建新的派生类,序列化程序将抛出错误。如果您必须使用派生类,那么您有两个选择:1) 在基类之上添加一个 XmlInclude 属性,每个派生类型一个,如下所示:[XmlInclude(typeof(TextboxControl))] 2) 序列化时使用自定义序列化器:'new XmlSerializer(typeof (Control),new Type[]{typeof(TextboxControl)});'
    • @AdamWhiteHat 这个函数在哪里 SerializeObject("SavedSlidePresentation.xml",mySlidePresentation);
    • @prakashkumarjha 我现在添加了SerializeObject 函数,很好。
    【解决方案2】:

    我之前做过一个类似的项目,我创建了两个字典来保存所有数据

    // Dictionary which Holds all the Info for the shapes in a Particular Slide
    Dictionary<Int32, ShapeInfo> slideInfoDict = new Dictionary<Int32, ShapeInfo>();
    
    // Dictionary which Holds all the Info for the all the shapes in the all the slides
    Dictionary<Int32, SlideInfo> appInfoDict = new Dictionary<Int32, SlideInfo>();
    

    我的“ShapeInfo”类包含有关各种形状(表格、矩形、图像等)的所有信息 此 shapeInfoDict 的键 (Int32) 是所选形状。

    “SlideInfo”类包含有关该特定幻灯片的所有信息。 此 slideInfoDict 的键 (Int32) 被选中 Slide。

    希望有所帮助。

    【讨论】:

      猜你喜欢
      • 2010-11-16
      • 1970-01-01
      • 2019-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-13
      • 1970-01-01
      相关资源
      最近更新 更多