wpf 如何将控件动态添加到另一个类中的 WrapPanel?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16366732/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 08:43:28  来源:igfitidea点击:

How to dynamically add controls to a WrapPanel in another class?

c#.netwpf

提问by WiredNewby

I'm migrating from VB to C# and decided that WPF would be the best option for me as the programs I've been developing are highly GUI dependant based applications. However, C# is causing me a lot of headaches, confusion, and frustration when trying to get what are simple tasks in VB to work in C# code. In VB, I can get this working VERY easily. But in C#, after spending countless hours (now days) searching and playing with code, I'm still non the wiser how to get this working.

我正在从 VB 迁移到 C#,并决定 WPF 将是我的最佳选择,因为我一直在开发的程序是高度依赖 GUI 的应用程序。然而,当我试图让 VB 中的简单任务在 C# 代码中工作时,C# 给我带来了很多头痛、困惑和挫折。在 VB 中,我可以很容易地做到这一点。但是在 C# 中,在花了无数个小时(现在是几天)搜索和玩代码之后,我仍然不知道如何让它工作。

My scenario:

我的场景:

  • I have 2 xaml pages.
  • The first xaml page has a wrappanel.
  • The second xaml page has a button that will create a new button and add it to the wrappanel in xaml page 1.
  • 我有 2 个 xaml 页面。
  • 第一个 xaml 页面有一个包装面板。
  • 第二个 xaml 页面有一个按钮,它将创建一个新按钮并将其添加到 xaml 页面 1 的包装面板中。

I can easily add a new button to the wrappanel when using the code below in page1.xaml.cs:

在 page1.xaml.cs 中使用以下代码时,我可以轻松地向包装面板添加一个新按钮:

Button New_Button = new Button();
My_WrapPanel.Children.Add(New_Button);

I've also tried calling a method located in page1 from page2 to create the button but the new button does not show in the wrappanel !?

我还尝试从 page2 调用位于 page1 中的方法来创建按钮,但新按钮未显示在包装面板中!?

I would really appreciate some help and possibly a simple code example to help me on my way.

我真的很感激一些帮助,可能还有一个简单的代码示例来帮助我。

回答by Federico Berasategui

Ok, Im using UserControls instead of Pages to keep them in a single Window. Since you didn't post any XAML, I have no idea what your real need is, but here is my take:

好的,我使用UserControls 而不是Pages 将它们保存在单个窗口中。由于您没有发布任何 XAML,我不知道您真正需要什么,但这是我的看法:

MultiPageSample.xaml ("Main Window"):

MultiPageSample.xaml(“主窗口”):

<Window x:Class="MiscSamples.MultiPageMVVM.MultiPageSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MiscSamples.MultiPageMVVM"
        Title="MultiPageSample" Height="300" Width="300">
    <UniformGrid Rows="1" Columns="2">
        <local:Page1 DataContext="{Binding Page1}"/>
        <local:Page2 DataContext="{Binding Page2}"/>
    </UniformGrid>
</Window>

Code Behind:

背后的代码:

public partial class MultiPageSample : Window
{
    public MultiPageSample()
    {
        InitializeComponent();

        DataContext = new MultiPageViewModel();
    }
}

ViewModel:

视图模型:

public class MultiPageViewModel
{
    public Page1ViewModel Page1 { get; set; }

    public Page2ViewModel Page2 { get; set; }

    public MultiPageViewModel()
    {
        Page1 = new Page1ViewModel();
        Page2 = new Page2ViewModel();

        Page2.AddNewCommand = new Command(Page1.AddCommand);
    }
}

Page1:

第1页:

<UserControl x:Class="MiscSamples.MultiPageMVVM.Page1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ItemsControl ItemsSource="{Binding Commands}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel IsItemsHost="True"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Button Command="{Binding}" Content="Click Me!"
                        Margin="2"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</UserControl>

Code Behind:

背后的代码:

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

Page2:

第2页:

<UserControl x:Class="MiscSamples.MultiPageMVVM.Page2"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Button Content="Add New Command (I Mean Button)"
            VerticalAlignment="Center" HorizontalAlignment="Center"
            Command="{Binding AddNewCommand}"/>
</UserControl>

Code Behind:

背后的代码:

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

ViewModel:

视图模型:

public class Page2ViewModel
{
    public Command AddNewCommand { get; set; }
}

Command class (can be found on most MVVM frameworks)

命令类(可以在大多数 MVVM 框架上找到)

//Dead-simple implementation of ICommand
    //Serves as an abstraction of Actions performed by the user via interaction with the UI (for instance, Button Click)
    public class Command : ICommand
    {
        public Action Action { get; set; }

        public void Execute(object parameter)
        {
            if (Action != null)
                Action();
        }

        public bool CanExecute(object parameter)
        {
            return IsEnabled;
        }

        private bool _isEnabled = true;
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                _isEnabled = value;
                if (CanExecuteChanged != null)
                    CanExecuteChanged(this, EventArgs.Empty);
            }
        }

        public event EventHandler CanExecuteChanged;

        public Command(Action action)
        {
            Action = action;
        }
    }

    public class Command<T>: ICommand
    {
        public Action<T> Action { get; set; }

        public void Execute(object parameter)
        {
            if (Action != null && parameter is T)
                Action((T)parameter);
        }

        public bool CanExecute(object parameter)
        {
            return IsEnabled;
        }

        private bool _isEnabled;
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                _isEnabled = value;
                if (CanExecuteChanged != null)
                    CanExecuteChanged(this, EventArgs.Empty);
            }
        }

        public event EventHandler CanExecuteChanged;

        public Command(Action<T> action)
        {
            Action = action;
        }
    }

Result:

结果:

enter image description here

在此处输入图片说明

Now, the explanation of all this mess:

现在,对所有这些混乱的解释:

First of all, you must leave behind the traditional mentalityof Manipulating UI elements in code, and embrace MVVM.

首先,你必须摒弃在代码操作UI元素的传统思维,拥抱MVVM

WPF has very powerful DataBindingcapabilities that are utterly absent in ancient dinosaur frameworks.

WPF 具有非常强大的DataBinding功能,这些功能在古代恐龙框架中是完全没有的。

Notice how I'm using the reusable Commandclass (which is kind of a basic part of most MVVM frameworks) to represent the Buttons in the Page1ViewModel. These instances of Commandare then added to the ObservableCollection, which in turn notifies WPF when an element is added or removed to it, and thus the UI is automatically updated by the Binding.

请注意我如何使用可重用Command类(这是大多数 MVVM 框架的基本部分)来表示 Page1ViewModel 中的按钮。Command然后将这些 的实例添加到 中ObservableCollection,当向其中添加或删除元素时,它反过来通知 WPF,因此 UI 由Binding.

Then, the DataTemplatedefined as the ItemTemplatefor the ItemsControlin Page1is used to "render" each item inside the ObservableCollection.

然后,DataTemplate定义为ItemTemplatefor ItemsControlinPage1的 用于“渲染” ObservableCollection.

This is what I refer to when I say WPF needs a really different mindset to work with. This is the default approach to EVERYTHING in WPF. You almost NEVER have the need to reference / create / manipulate UI elements in procedural code. That's what XAML is for.

当我说 WPF 需要一种真正不同的思维方式来使用时,这就是我所指的。这是 WPF 中所有内容的默认方法。您几乎不需要在程序代码中引用/创建/操作 UI 元素。这就是 XAML 的用途。

Also notice that this could be simplified A LOT by using the same ViewModelfor both Pages, but I kept them separate on purpose just to show you this case where you have different ViewModels communicating with each other directly.

另请注意,这可以通过ViewModel对两个Pages使用相同的内容来简化很多,但我故意将它们分开只是为了向您展示这种情况,即您有不同的 ViewModel 直接相互通信。

Let me know if you have any doubts.

如果您有任何疑问,请告诉我。