简体   繁体   English

如何制作动态C#控件

[英]how to make a dynamic C# control

I am working on a project and need some help with bindings... 我正在做一个项目,需要一些有关绑定的帮助...

I have a list of products, that can belong to a distribution center. 我有一个产品列表,可以属于一个配送中心。 I would like to create a dynamic form, ie, one that can decide for itself what content it should display, based on the availability of information. 我想创建一个动态表格,即可以根据信息的可用性自行决定应显示的内容。

Basically, The distribution currently have 3 products that it can report on, but that number is variable. 基本上,该发行版目前可以报告3种产品,但是该数字是可变的。 It should display 3 entries right now, but should there be more (or less) it should be able to handle it. 它现在应该显示3个条目,但是应该能够处理更多(或更少)条目。

For instance, I would like to bind the DistributionCenter's Name property to a type of header label, and the different product names, along with the quantity of each one, should be displayed as two labels (the dynamic part). 例如,我想将DistributionCenter的Name属性绑定到一种标题标签,并且不同的产品名称以及每个产品的数量应显示为两个标签(动态部分)。

I hope I make sense. 我希望我有道理。 Here is the model code, the GUI is not implemented yet, as I do need help with that part. 这是模型代码,尚未实现GUI,因为我确实需要该部分的帮助。

namespace Stock
{
    public partial class MainWindow : Window
    {
        public class Product
        {
            // accessors
            public string Code { get; set; }
            public string Name { get; set; }
            public int Quantity { get; set; }
            private int Threshold { get; set; }

            // constructor
            public Product(string code, string name, int quantity, int threshold)
            {
                this.Code = code;
                this.Name = name;
                this.Quantity = quantity;
                this.Threshold = threshold;
            }
        }
        public class DistributionCentre
        {
            // accessors
            public string Name { get; set; }
            public List<Product> p = new List<Product>();

            // constructor
            public DistributionCentre(string name, Product product)
            {
                this.p.Add(product);
            }
        }

        public class StockEngine
        {
            public StockEngine()
            {
                // register a few products
                Product p1 = new Product("1001", "Product1", 10, 5);
                Product p2 = new Product("1002", "Product2", 6, 5);
                Product p3 = new Product("1003", "Product3", 8, 5);

                // assign these products to a DC
                DistributionCentre ClinicA = new DistributionCentre("DC1", p1);
            }
        }

        public MainWindow()
        {            
            StockEngine control = new StockEngine();
            InitializeComponent();
        }
    }

Edit: I have additionally created the following control, and would like to bind the controls to the relevant members of the C# classes. 编辑:我另外创建了以下控件,并希望将控件绑定到C#类的相关成员。 Any help on this will much be appreciated. 在这方面的任何帮助将不胜感激。

<UserControl x:Class="Stock.ReportingCard"
         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="37" d:DesignWidth="300">
<Grid Height="35">
    <Label Content="Product" Height="25" HorizontalAlignment="Left" Name="Product" VerticalAlignment="Top" Width="67" Margin="5,5,0,0" />
    <Label Content="Quantity" Height="30" HorizontalAlignment="Left" Margin="78,5,0,0" Name="Quantity" VerticalAlignment="Top" Width="59" />
    <Button Content="Plus" Height="24" HorizontalAlignment="Left" Margin="171,6,0,0" Name="PlusButton" VerticalAlignment="Top" Width="44" />
    <Button Content="Minus" Height="24" HorizontalAlignment="Left" Margin="233,6,0,0" Name="MinusButton" VerticalAlignment="Top" Width="44" />
</Grid>

Hello @Harriet to be honest I see a lot of issues in the provided code but I'm not going to address most of them as it's also a little bit subjective, also I feel like your question is too broad and somewhat misleading but I will address the part of it that got me interested and give you some pointers and example how to fix that part. 您好@Harriet,老实说,我在所提供的代码中看到了很多问题,但由于其中有些主观性,所以我将不解决大多数问题,我也觉得您的问题过于笼统,有些误导,但我会解决引起我兴趣的部分,并提供一些指导和示例,说明如何修复该部分。

For simplicity I'll not go with the whole structure that you provided also note that for the bindings to work as expected (eg you change something in your view model -> your UI updates and vice versa), you need to implement INotifyPropertyChanged or use some MVVM framework like MVVM Light , Prism etc... that does that for you (with a lot more stuff) 为简单起见,我不会使用您提供的整个结构,还要注意,要使绑定按预期工作(例如,更改视图模型中的某些内容-> UI更新,反之亦然),则需要实现INotifyPropertyChanged或使用一些MVVM框架,例如MVVM LightPrism等...为您做到了(还有更多东西)

So the issue that we'll fix is the one of having different (Dynamic) Controls for the different types of products (Not sure if you even had that in mind, but that's my understanding of dynamic control) 因此,我们要解决的问题是对不同类型的产品使用不同的(动态)控件(不确定您是否牢记这一点,但这是我对动态控件的理解)

We'll be using one of the two approaches that I like for solving this kind of issue from MSDN, slightly modified example version of: DataTemplateSelector 我们将使用我喜欢的两种方法之一来解决MSDN上的此类问题,对以下示例版本进行了稍微修改: DataTemplateSelector

(The other one that I've used and like here: WPF Based Dynamic DataTemplateSelector ) (我在这里使用并喜欢的另一个: 基于WPF的Dynamic DataTemplateSelector

public class ProductsDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        FrameworkElement element = container as FrameworkElement;

        if (element != null && item != null && item is Product)
        {
            Product productitem = item as Product;

            if (productitem.Code == "1001" || productitem.Code == "1003")
            {
                return element.FindResource("1001ProductTemplate") as DataTemplate;
            }
            else if (productitem.Code == "1002")
            {
                return element.FindResource("1002ProductTemplate") as DataTemplate;
            }
            else
            {
                return element.FindResource("UnknownProductTemplate") as DataTemplate;
            }
        }

        return null;
    }
}

This is the XAML to illustrate 3 different types of dynamic controls and a ListView containing all the products that we defined in the code behind 这是XAML,用于说明3种不同类型的动态控件和一个ListView,其中包含我们在后面的代码中定义的所有产品

    <DataTemplate x:Key="1001ProductTemplate">
        <Grid Height="35" Background="Red">
            <Label Content="{Binding Path=Name}" Height="25" HorizontalAlignment="Left" Name="Product" VerticalAlignment="Top" Width="67" Margin="5,5,0,0" />
            <Label Content="{Binding Path=Quantity}" Height="30" HorizontalAlignment="Left" Margin="78,5,0,0" Name="Quantity" VerticalAlignment="Top" Width="59" />
            <Button Content="Plus" Height="24" HorizontalAlignment="Left" Margin="171,6,0,0" Name="PlusButton" VerticalAlignment="Top" Width="44" />
            <Button Content="Minus" Height="24" HorizontalAlignment="Left" Margin="233,6,0,0" Name="MinusButton" VerticalAlignment="Top" Width="44" />
        </Grid>
    </DataTemplate>

    <DataTemplate x:Key="1002ProductTemplate">
        <Grid Height="35" Background="Green">
            <Label Content="{Binding Path=Name}" Height="25" HorizontalAlignment="Left" Name="Product" VerticalAlignment="Top" Width="67" Margin="5,5,0,0" />
            <Label Content="{Binding Path=Quantity}" Height="30" HorizontalAlignment="Left" Margin="78,5,0,0" Name="Quantity" VerticalAlignment="Top" Width="59" />
            <Button Content="Minus" Height="24" HorizontalAlignment="Left" Margin="233,6,0,0" Name="MinusButton" VerticalAlignment="Top" Width="44" />
            <Button Content="Plus" Height="24" HorizontalAlignment="Left" Margin="171,6,0,0" Name="PlusButton" VerticalAlignment="Top" Width="44" />
        </Grid>
    </DataTemplate>

    <DataTemplate x:Key="UnknownProductTemplate">
        <Grid Height="35" Background="Blue">
            <Label Content="{Binding Path=Name}" Height="25" HorizontalAlignment="Left" Name="Product" VerticalAlignment="Top" Width="67" Margin="5,5,0,0" />
            <Label Content="{Binding Path=Quantity}" Height="30" HorizontalAlignment="Left" Margin="78,5,0,0" Name="Quantity" VerticalAlignment="Top" Width="59" />
        </Grid>
    </DataTemplate>

</Window.Resources>

<Grid>
    <ListView ItemTemplateSelector="{StaticResource ResourceKey=productDTSelector}"
              x:Name="ListView">

    </ListView>
</Grid>

We'll use just a simple list of products in the code behind 我们将在后面的代码中仅使用产品的简单列表

public MainWindow()
{
    InitializeComponent();
    //StockEngine control = new StockEngine();

    var products = new List<Product>();

    Product p1 = new Product("1001", "Product1", 10, 5);
    Product p2 = new Product("1002", "Product2", 6, 5);
    Product p3 = new Product("1003", "Product3", 8, 5);
    Product p4 = new Product("999", "Some Prod", 8, 5);
    Product p5 = new Product("1002", "Product4", 10, 10);

    products.Add(p1);
    products.Add(p2);
    products.Add(p3);
    products.Add(p4);
    products.Add(p5);

    ListView.ItemsSource = products;
}

So what all this code does is: Have a ListView with source - your products, the template selector is responsible for returning the correct template for each product in the collection (depending on their code). 因此,这些代码的全部作用是:有一个带有源的ListView-您的产品,模板选择器负责为集合中的每个产品返回正确的模板(取决于它们的代码)。 Different templates are illustrated with different structure or style of the controls (I've used your example control and just added some simple bindings to the product's properties) 展示了具有不同结构或样式的控件的不同模板(我已经使用了示例控件,只是向产品属性添加了一些简单的绑定)

Please if anyone finds this answer to be off-topic and not helpful let me know and I'll put it down. 如果有人发现此答案是题外话,对您没有帮助,请告诉我,我会予以保留。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM