在VB.Net中将多个基于XAML的WPF控件动态添加到Canvas [英] Add multiple XAML based WPF control to Canvas dynamically in VB.Net

查看:150
本文介绍了在VB.Net中将多个基于XAML的WPF控件动态添加到Canvas的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

像主题一样,我想添加WPF控件,但模板要相同,但要动态添加不同的数据。

As like the subject, I want to add WPF controls of the same template but different data inside as many as I want dynamically.

图片,我要复制的控件有些复杂。整体控件包装在 ScrollViewer Canvas 内部。
每个 StackPanel 包装 TextBlock 另一个 Canvas控制和我想要复制的 StackPanel

As you can see in the picture, the control that I want to duplicate is somewhat complicated. The overall control is wrapped inside Canvas inside ScrollViewer. Each StackPanel wraps TextBlock and another Canvas Control and this StackPanel is what I want to reproduce.

它的编码如下:

<ScrollViewer x:Name="ScrollBoard" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
            <Canvas x:Name="CanvasBoard" VerticalAlignment="Center" HorizontalAlignment="Center" Width="200" Height="250" Background="Gray">

                <StackPanel x:Name="CanvasStack" Background="DimGray">
                    <CheckBox />

                    <Border x:Name="CanvasBorder" BorderBrush="Black" BorderThickness="1">
                        <Canvas Width="150" Height="200" ClipToBounds="True">

                            <Image x:Name="CanvasImage" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Source="C:\test.jpg"/>

                        </Canvas>
                    </Border>

                    <TextBlock Text="Test.jpg" />
                </StackPanel>

            </Canvas>
        </ScrollViewer>

我想复制 CanvasBoard Canvas 中的 CanvasStack StackPanel 控件控制。

I want to duplicate that CanvasStack StackPanel control inside CanvasBoard Canvas Control.

当然,不仅是重复的,而且还想控制它。
例如,更改位置,编辑 TextBlock 文本,替换 Image 并获得 Click 事件,等等。

Of course, not just duplicate but also want to take control of that. For example, change the position, edit TextBlock text, replace Image and get Click event and so on.

此外,我不会使用 ListBox 之所以使用ListView ,是因为每个控件都应位于具有各种大小的绝对x,y坐标中。

Plus, I will not use ListBox or ListView for it because each Control should be located in absolute x,y coordination with various size.

有些示例在执行类似为特定控件添加按钮。但是我发现只是在后端添加了具有硬编码属性的控件,这些属性可能不适合这种复杂的控件。

There are some examples doing similar things like 'adding a button to certain control'. But what I found were just add control in backend with hard-coded properties which may not fit for this kind of complex control.

请先谢谢您。

推荐答案

每当您打算多次创建相同的ui时,就应该考虑模板。

Whenever you're thinking of creating the same ui numerous times then you should think in terms of templating.

当您想要更改任何内容的属性时,您应该考虑数据模板,并将这些更改的内容绑定到视图模型的公共属性。

When you want properties of anything to change then you should think in terms of a datatemplate and bind those changing things to a public property of a viewmodel.

如果在同一区域中有重复的控件,则第一个候选对象应该是某种itemscontrol。

With repeated controls in the same area the first candidate should be some sort of an itemscontrol.

其中有一个堆栈面板可以容纳所有内容,但是您可以轻松地更改它

That has a stackpanel in it holds everything - but you can easily change that.

对于一块画布上的许多东西,您可以使一个项目的面板控制一个画布。

For numerous things on one canvas you can make the itemspanel of an itemscontrol a canvas.

并不是绝对需要用户控件来封装您的标记,您只需拥有一个数据模板即可。

You don't absolutely need a usercontrol to encapsulate your markup, you can just have a datatemplate.

为窗口构建一个视图模型s。为每个要复制的事物构建一个视图模型(vm)。

Build a viewmodel for your windows. Build a viewmodel for each of these things you want to reproduce (vm).

将可观察到的vm集合绑定到itemscontrol的itemssource。

Bind an observablecollection of vm to the itemssource of an itemscontrol.

定义与该类型的视图模型关联的数据模板。

Define a datatemplate associated with that type of viewmodel.

我在c#中工作,因此如果尝试并编写VB代码。通过在线转换器运行以下代码。

I work in c# so I'm likely to get something wrong if I try and write VB code. Run the code below through an online converter.

标记:

<Window.DataContext>
    <local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
    <ItemsControl x:Name="ic" ItemsSource="{Binding Items}">
        <ItemsControl.Resources>
            <DataTemplate DataType="{x:Type local:StackyVM}">
                <StackPanel x:Name="CanvasStack" Background="DimGray">
                    <CheckBox />
                    <Border x:Name="CanvasBorder" BorderBrush="Black" BorderThickness="1">
                        <Canvas Width="150" Height="200" ClipToBounds="True">

                            <Image x:Name="CanvasImage" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" 
                                   Source="{Binding ImageSource}"/>
                        </Canvas>
                    </Border>
                    <TextBlock Text="Test.jpg" />
                </StackPanel>
            </DataTemplate>
        </ItemsControl.Resources>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Name="TheCanvas"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Top" Value="{Binding Top}"/>
                <Setter Property="Canvas.Left" Value="{Binding Left}"/>
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>

每个堆栈的视图模型

public class StackyVM : BaseViewModel
{
    private Double left;

    public Double Left
    {
        get { return left; }
        set
        {
            left = value;
            RaisePropertyChanged();
        }
    }

    private Double top;

    public Double Top
    {
        get { return top; }
        set { top = value; RaisePropertyChanged(); }
    }

    public string ImageUrl { get; set; }

}

添加任何其他属性,这些属性随堆栈和捆绑它们。
实例化每个堆栈中的一个,并将其添加到绑定的observablecollection中:

Add any other properties which will vary for each stack and bind them. Instantiate one of those for each stack and add it to the bound observablecollection:

public class MainWindowViewModel : BaseViewModel
{
    public ObservableCollection<StackyVM> Items { get; set; }

每个模板都将被模板化到堆栈中。

Each will then be templated into a stack.

BaseViewModel实现了inotifypropertychanged:

BaseViewModel implements inotifypropertychanged:

public  class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

这篇关于在VB.Net中将多个基于XAML的WPF控件动态添加到Canvas的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆