【问题标题】:WPF C# user control with 2 or more buttons带有 2 个或更多按钮的 WPF C# 用户控件
【发布时间】:2020-07-09 17:27:38
【问题描述】:

很抱歉,如果以前有人问过这个问题,我花了大约一周的时间试图找到一个类似的问题来为我指明正确的方向。我正在用 WPF、XAML 等自学 C#,并且正在玩用户控件。我制作了一个带有用户控件的简单应用程序,可以加载到其他窗口或用户控件之上。有问题的 UC 有两个按钮,一旦加载控件,我需要获取主窗口中每个按钮的点击事件。主窗口有一个加载控件的按钮。

通过一些研究,我能够从用户 SWilko (https://stackoverflow.com/a/28949666/10659981) 那里找到解决方案,但我无法分别为每个按钮找出解决方案(单击按钮 a 并显示“clicked btn a”,单击按钮 b 并显示“单击按钮 b”)。我确实尝试使用名称由发件人拨打电话,但这也不起作用。在 SWilko 的回答的帮助下,我觉得我很接近但卡住了。

到目前为止的代码如下: 基本的主屏幕加载用户控件

    <Window x:Class="UCBTN_TEST.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:UCBTN_TEST"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="435">
        <Grid>
            <Button Content="Load Button" HorizontalAlignment="Left" Margin="18,23,0,0" VerticalAlignment="Top" Width="74" Click="Button_Click"/>
            <Grid x:Name="GridLoad" HorizontalAlignment="Left" Height="300" Margin="120,23,0,0" VerticalAlignment="Top" Width="300" Background="#FFF1CBCB"/>
    
        </Grid>
    </Window>
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace UCBTN_TEST
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                GridLoad.Children.Clear();
                GridLoad.Children.Add(new WindowControl());
            }
        }
    }

按钮用户控件

    <UserControl x:Name="UCMain" x:Class="UCBTN_TEST.Controls.ButtonControl"
                 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" 
                 xmlns:local="clr-namespace:UCBTN_TEST.Controls"
                 mc:Ignorable="d" d:DesignWidth="300" Height="40.333">
        
        <Grid Background="#FFE7EEA7">
            <Button x:Name="ButtonA" Content="Button A" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="ButtonA_Click" Background="Red"/>
            <Button x:Name="ButtonB" Content="Button B" HorizontalAlignment="Left" Margin="215,10,0,0" VerticalAlignment="Top" Width="75" Click="ButtonA_Click" Background="Green"/>
        </Grid>
    </UserControl>
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace UCBTN_TEST.Controls
    {
        /// <summary>
        /// Interaction logic for ButtonControl.xaml
        /// </summary>
        public partial class ButtonControl : UserControl
        {
            public ButtonControl()
            {
                InitializeComponent();
            }
    
            private void ButtonA_Click(object sender, RoutedEventArgs e)
            {
                RaiseEvent(new RoutedEventArgs(ClickEvent1, this));
            }
    
            public static readonly RoutedEvent ClickEvent1 = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ButtonControl));
    
            public event RoutedEventHandler Click
            {
                add { AddHandler(ClickEvent1, value); }
                remove { RemoveHandler(ClickEvent1, value); }           
            }
        }
    }

一旦按钮正常工作,第二个用户控件最终将具有其他一些控件。但是 UC 按钮会加载在上面,与 WindowControl 相关的简单按钮功能。

    <UserControl
                 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" 
                 xmlns:local="clr-namespace:UCBTN_TEST"
                 xmlns:Controls="clr-namespace:UCBTN_TEST.Controls" x:Class="UCBTN_TEST.WindowControl"
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
    
        <Grid Background="#FFE7CFEE">
            <Controls:ButtonControl HorizontalAlignment="Left" Height="37" VerticalAlignment="Top" Width="300" Click="Click1"/>
        </Grid>
    
    </UserControl>

我了解背后的代码以及发生这种情况的原因。我的问题是我需要让按钮在他们的事件中是唯一的。我曾尝试按发件人和姓名进行呼叫,但这只是将事件一起杀死。

    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using UCBTN_TEST.Controls;
    
    namespace UCBTN_TEST
    {
        /// <summary>
        /// Interaction logic for WindowControl.xaml
        /// </summary>
        public partial class WindowControl : UserControl
        {
    
            public WindowControl()
            {
                InitializeComponent();            
            }
    
            private void Click1(object sender, RoutedEventArgs e)
            {
                
                MessageBox.Show("This triggers both");
                
            }
        }
    }

【问题讨论】:

  • 我浏览了您的问题,但我认为您会收到两个消息框,因为您在 xaml 中为用户控件指定了点击回调。
  • 正确,它们都共享相同的点击事件名称,ButtonA_Click。这个想法是在 WindowControl cs 中通过名称来区分,不幸的是我尝试过的所有方法都没有奏效。
  • 我的意思是你的路由不工作。它只是在用户控件上执行点击事件。从我略读的内容中。

标签: c# wpf


【解决方案1】:

我本来打算添加一堆 cmets,但这实际上是在回答问题,还有很多要解释的。

您应该研究 MVVM,并且主要考虑绑定命令而不是单击哪个按钮。这也有例外。例如,如果您正在构建屏幕键盘。这是不同的原因,因为它的目的可以被封装。用户按下其中包含“A”的按钮。无论文本框的焦点是什么,都应该发送字符“A”。他们按下一个显示“B”的按钮,同样应该发送“B”。该功能可以封装在控件中。

实际上,您有两个按钮。

您将它们放在用户控件中并封装它们。

通过这样做,您创建了一个边界。

这会产生一个复杂的问题 - 被点击了?

用户控件也不是特别友好的重用。如果添加两个,则有两个按钮 A 和两个按钮 B。您可以通过自定义路由事件上的自定义事件参数和用户控件上的依赖属性来改进它。传递一些用户控件标识符以及按下的按钮。

不过,这将是一种不同寻常的工作方式。我很少看到在商业应用中使用自定义路由事件。

总而言之,我建议用户控件主要增加复杂性。

假设您想要 20 组 2 个按钮。

或 20 组 5 个单选按钮用于一组多项选择题。

做这种事情的方法是使用一个itemscontrol 和模板出多个控件。一个模板,每行提供 2 个按钮(或一个文本块问题和 5 个单选按钮用于回答)。

点击事件已经是一个路由事件,并且会冒泡到窗口。您也可以将自定义路由事件和处理程序从用户控件中删除...和用户控件。只需在窗口中处理点击即可。

代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var btn = e.OriginalSource as Button;
        if(btn == null)
        {
            return;
        }

        MessageBox.Show($"Button clicked was {btn.Tag}");
    }

标记:

    ButtonBase.Click="Button_Click"
    Title="MainWindow" 
        >
    <Grid>
        <StackPanel>
            <Button x:Name="ButtonA" Content="Button A" Tag="A" Background="Red"/>
            <Button x:Name="ButtonB" Content="Button B" Tag="B" Background="Green"/>
        </StackPanel>
    </Grid>
    </Window>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-15
    • 1970-01-01
    • 1970-01-01
    • 2018-12-23
    • 2011-11-28
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多