3

I need to write a Windows Form where the user can view many "contracts" grouped by "customer". Each customer must be a expand-collapse panel, and the contracts of the customer must be inside of the corresponding panel.

I already tried the great ExpandCollapsePanel, but when the number of customers is big then the panel doesn't autoscroll, even with the AutoScroll property set to true.

Does anybody know some other alternatives? Remember the panels must be dynamically created because there are many customers and many contracts belonging to each customers.

Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63
wind39
  • 441
  • 4
  • 14
  • 1
    You should keep your UI as simple as possible when using `winforms`, if it's a requirement, you should consider some third-party UI library which supports rich set of controls. Complicating the UI is only recommended if you use `WPF`, customizing your own complicated control is a pain and also buggy, I've experienced such a pain in a project, hardly to forget it. – King King Oct 22 '13 at 17:49
  • Agree with @KingKing, you can achieve this in WPF with a simple [ListBox](http://wpftutorial.net/images/listbox_datatemplate3.png), all while maintaining [UI Virtualization](http://www.youtube.com/watch?v=D3Y6DnFpHCA) to deal with whatever amounts of data without losing performance, whereas trying something like that in winforms is going to be like hell. – Federico Berasategui Oct 22 '13 at 18:22
  • I got your point, this video @HighCore sent shows how superior WPF is over WinForms in performance. Never used WPF before :( – wind39 Oct 22 '13 at 19:06
  • @wind39 [this video](http://www.istartedsomething.com/20091124/razorfone-conceptual-windows7-wpf-multi-touch-retail/) demonstrates why WPF is really preferred over winforms for .Net Windows applications. If you are working in an existing winforms project, and need to introduce complex (rich) UI features, you can use an `ElementHost` to host WPF content inside a `Form` or panel. Let me know if that is an option for you and I can provide some sample code. – Federico Berasategui Oct 22 '13 at 19:08
  • @HighCore Great video! I didn't know about ElementHost, it is really suitable to our application. I'd be glad if you provide some sample code, thanks! – wind39 Oct 23 '13 at 12:24
  • Suggesting another interface system is NOT an answer to the question posed. There are many other systems one could use. Please answer the question as it pertains to the use of C# WinForms. – Mike Pliam Sep 26 '20 at 18:02

1 Answers1

3

Ok, I've created a sample using an ElementHost to host a WPF UserControl, it looks like this:

enter image description here

I've uploaded the full source code Here, but anyways these are the most relevant parts:

Form1:

public partial class Form1 : Form
{
    public CustomerContractsViewModel ContractsVM { get; set; }

    public Form1()
    {
        InitializeComponent();

        ContractsVM  = new CustomerContractsViewModel();

        var customercontractsview = new CustomerContractsView(){DataContext = ContractsVM};

        var elementHost = new ElementHost() { Dock = DockStyle.Fill };
        elementHost.Child = customercontractsview;

        panel1.Controls.Add(elementHost);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        ContractsVM.LoadCustomers(DataSource.GetCustomers());
    }
}

(Designer code omitted for brevity)

WPF View:

<UserControl x:Class="ElementHostSamples.CustomerContractsView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <!-- This style is applied to all Label elements within the UserControl-->
        <Style TargetType="Label">
            <Setter Property="FontWeight" Value="Bold"/>
            <Setter Property="HorizontalAlignment" Value="Right"/>
        </Style>

        <!-- This DataTemplate will be used to render the Contract items-->
        <DataTemplate x:Key="ContractTemplate">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>

                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>

                <Label Grid.Row="0" Grid.Column="0" Content="Contract Date:"/>
                <Label Grid.Row="1" Grid.Column="0" Content="Amount:"/>

                <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding ContractDate, StringFormat='MM/dd/yyyy'}" VerticalAlignment="Center"/>
                <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Amount, StringFormat=C}" VerticalAlignment="Center"/>
            </Grid>
        </DataTemplate>

        <!-- This DataTemplate will be used to render the Customer Items -->
        <DataTemplate x:Key="CustomerTemplate">
            <Expander Header="{Binding Name}">
                <ListBox ItemsSource="{Binding Contracts}" ItemTemplate="{StaticResource ContractTemplate}">
                    <ListBox.Template>
                        <ControlTemplate TargetType="ListBox">
                            <ItemsPresenter/>
                        </ControlTemplate>
                    </ListBox.Template>
                </ListBox>
            </Expander>
        </DataTemplate>
    </UserControl.Resources>

    <ListBox ItemsSource="{Binding Customers}"
             ItemTemplate="{StaticResource CustomerTemplate}"/>
</UserControl>

Code Behind:

public partial class CustomerContractsView : UserControl
{
    public CustomerContractsView()
    {
        InitializeComponent();
    }
}

ViewModel:

public class CustomerContractsViewModel:PropertyChangedBase
{
    public List<Customer> Customers { get; set; }

    public void LoadCustomers(List<Customer> customers)
    {
        Customers = customers;
        OnPropertyChanged("Customers");
    }
}
  • Notice how this simple, less than 100 lines of code, 20-minute WPF sample is better than anything you can ever hope to achieve in winforms, and doesn't need any "owner draw", "P/Invoke" (whatever that means) or horrendous gargantuan code behind stuff. And does not force you to spend lots of money in third party components such as DevExpress or Telerik. This is why WPF is the best option for ALL .Net Windows Desktop application development, regardless if it's a simple Hello World type of stuff.

  • I'm using an ItemsControl to host the Customer items, and inside these I'm using a ListBox with a custom DataTemplate to show the Contract items.

  • Both ItemsControl (outer and inner) are Virtualized to enable an immediate response time, even with 200,000 items.

  • Notice that there's not a single line of code that interacts with the UserControls' UI Elements, Everything is defined in XAML and populated with data via DataBinding. This enables a great amount of scalability and maintainability because the UI is completely decoupled from the application logic / business logic. That's the WPF way.

  • The Form code (except for the initialization code) only interacts with the ViewModel, and has no need to interact with the WPF View.

  • When upgrading from winforms to WPF, you seriously need to embrace The WPF Mentality, which is, as mentioned before, you almost never manipulate UI elements in procedural code, or use too much code behind, but rather use DataBinding for everything and embrace The MVVM Pattern

  • WPF Rocks. Download the linked source code and see the results for yourself.

  • Let me know if you need further help.
Community
  • 1
  • 1
Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
  • 2
    Both WPF and you rock, @HighCore! How can I say how thankful I am? You solve our problem: 1) in few minutes; 2) the best way; 3) the fastest way; 4) with clean, intuitive, mantainable code; 5) with a high quality documentation, convincing me why WPF is superior over WinForms. Most important, now I will learn this technology and use it in other situations. Thank you very much! – wind39 Oct 24 '13 at 17:22