Пользовательский элемент управления типом представления карточки C#

Я новичок, пишу программу викторины в программе С# Winforms. По сути, я хотел бы иметь возможность отображать пары вопросов и ответов в серии «карточек». Каждая карточка должна иметь возможность отображать текст и иметь некоторые другие функции с помощью кнопки или двух.

элемент управления карточкой devexpress немного похоже на то, что я хотел бы. Но цена запредельная.

Я не уверен, что ответ заключается в создании пользовательского элемента управления, который копируется для каждого элемента данных во время выполнения?

Я был бы признателен, если бы меня указали в правильном направлении, поскольку я, кажется, застрял на этом некоторое время и не знаю, с чего начать.


person GordonBooker    schedule 10.07.2017    source источник
comment
Решений много: 1) сделать свой контрол, при его создании вы многое узнаете об контролах winforms; 2) сделать панель с элементами на ней; 3) сделать фотобокс и использовать его по своему усмотрению, заполняя его текстами и изображениями.   -  person KamikyIT    schedule 10.07.2017


Ответы (1)


Элементы управления Dev Express предназначены для богатых людей, мы, бедняки, можем реализовать свои собственные!

Вам нужно будет создать элемент управления CardsPanel с коллекцией CardViewModel. Очевидно, что он прочитает каждый элемент коллекции, создаст для него элемент управления Card, установит его модель представления и добавит в Panel. Вы в принципе сами ответили на свой вопрос!

Что касается приятного плавного движения внутри этого CardControl, может потребоваться некоторый код для добавления Lerp и Slerp, но это не должно быть слишком сложно. Вы можете отслеживать пополнения коллекции с помощью ObservableCollection, когда это необходимо. По вашей ссылке дизайн кажется очень простым, и его не составит труда подражать обычным Winforms.

Вот полный пример:

public class CardsPanel : Panel
{
    const int CardWidth = 200;
    const int CardHeight = 150;

    public CardsViewModel ViewModel { get; set; }

    public CardsPanel()
    {
    }
    public CardsPanel(CardsViewModel viewModel)
    {
        ViewModel = viewModel;
        ViewModel.Cards.CollectionChanged += Cards_CollectionChanged;
    }

    private void Cards_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        DataBind();
    }

    public void DataBind()
    {
        SuspendLayout();
        Controls.Clear();

        for(int i = 0; i < ViewModel.Cards.Count; i++)
        {
            var newCtl = new CardControl(ViewModel.Cards[i]);
            newCtl.DataBind();
            SetCardControlLayout(newCtl, i);
            Controls.Add(newCtl);
        }
        ResumeLayout();
    }

    void SetCardControlLayout(CardControl ctl, int atIndex)
    {
        ctl.Width = CardWidth;
        ctl.Height = CardHeight;

        //calc visible column count
        int columnCount = Width / CardWidth;

        //calc the x index and y index.
        int xPos = (atIndex % columnCount) * CardWidth;
        int yPos = (atIndex / columnCount) * CardHeight;

        ctl.Location = new Point(xPos, yPos);
    }
}

public partial class CardControl : UserControl
{
    public CardViewModel ViewModel { get; set; }

    public CardControl()
    {
        InitializeComponent();
    }
    public CardControl(CardViewModel viewModel)
    {
        ViewModel = viewModel;
        InitializeComponent();
    }

    public void DataBind()
    {
        SuspendLayout();

        tbAge.Text = ViewModel.Age.ToString();
        tbAge.Name = ViewModel.Name;
        pbPicture.Image = ViewModel.Picture;

        ResumeLayout();
    }
}

public class CardsViewModel
{
    public ObservableCollection<CardViewModel> Cards { get; set; }
}

public class CardViewModel
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Bitmap Picture { get; set; }
}

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        cardsPanel1.ViewModel = LoadSomeData();
        cardsPanel1.DataBind();
    }

    private CardsViewModel LoadSomeData()
    {
        ObservableCollection<CardViewModel> cards = new ObservableCollection<CardViewModel>();
        cards.Add(new CardViewModel()
        {
            Age = 1,
            Name = "Dan",
            Picture = new Bitmap(Image.FromFile("C:\\Users\\daniel.rayson\\Pictures\\CuteKitten1.jpg"))
        });
        cards.Add(new CardViewModel()
        {
            Age = 2,
            Name = "Gill",
            Picture = new Bitmap(Image.FromFile("C:\\Users\\daniel.rayson\\Pictures\\CuteKitten1.jpg"))
        });
        cards.Add(new CardViewModel()
        {
            Age = 3,
            Name = "Glyn",
            Picture = new Bitmap(Image.FromFile("C:\\Users\\daniel.rayson\\Pictures\\CuteKitten1.jpg"))
        });
        cards.Add(new CardViewModel()
        {
            Age = 4,
            Name = "Lorna",
            Picture = new Bitmap(Image.FromFile("C:\\Users\\daniel.rayson\\Pictures\\CuteKitten1.jpg"))
        });
        cards.Add(new CardViewModel()
        {
            Age = 5,
            Name = "Holly",
            Picture = new Bitmap(Image.FromFile("C:\\Users\\daniel.rayson\\Pictures\\CuteKitten1.jpg"))
        });            
        CardsViewModel VM = new CardsViewModel()
        {
            Cards = cards
        };
        return VM;
    }
}

Вы можете видеть здесь, что я вставил туда некоторые данные тестирования, но общие концепции уже есть, и это основа, с которой вы можете спрыгнуть.

Удачи!

person Dan Rayson    schedule 10.07.2017
comment
Может быть, FlowLayoutPanel является лучшим вариантом для базового класса CardsPanel? - person Marco Guignard; 12.10.2017