简体   繁体   English

在 WPF/C# 中,如何访问动态生成的控件的元素或以其他方式向它们添加单击事件?

[英]In WPF/C#, how do I access elements of dynamically generated controls or otherwise add click events to them?

I am using a custom control class to build similar-looking controls with different details and OnClick actions.我正在使用自定义控件 class 来构建具有不同细节和 OnClick 操作的外观相似的控件。 Other than looking pretty, the controls only function is to toggle a yellow button so it looks like a modern togglebutton control (like in Android settings or whatever).除了看起来漂亮之外,只有 function 的控件用于切换黄色按钮,因此它看起来像现代的切换按钮控件(如 Android 设置或其他)。

The main output looks like this:主要的 output 看起来像这样: 带有自定义控件的主输出

What I'm trying to do is figure out how to bring the "onclick" logic out of the control and into the main file so I can properly respond to it.我想做的是弄清楚如何将“onclick”逻辑从控件中移出并放入主文件中,以便我可以正确地响应它。 I originally had it respond to it's own click events on both the rectangle and ellipse like so:我最初让它响应它自己在矩形和椭圆上的点击事件,如下所示:

    public partial class FixerBox : UserControl
    {
        Thickness btnDotOn = new Thickness(-60, 0, 0, 0);
        Thickness btnDotOff = new Thickness(0, 0, -60, 0);
        SolidColorBrush dotOn = new SolidColorBrush(Color.FromRgb(84, 130, 53));
        SolidColorBrush dotOff = new SolidColorBrush(Color.FromRgb(207, 178, 76));
        SolidColorBrush bkOn = new SolidColorBrush(Color.FromRgb(226, 240, 217));
        SolidColorBrush bkOff = new SolidColorBrush(Color.FromRgb(255, 242, 204));
        
        public bool IsOn { get; set; } = false;
        
        public FixerBox(Dictionary<string,string> deets)
        {
            InitializeComponent();
            btnOff();
            this.Name = deets["Name"];
            this.FixerTitle.Text = deets["Title"];
            this.FixerDesc.Text = deets["Description"];
            this.FixerTags.Text = deets["Tags"];
            this.FixerImg.Source = new BitmapImage(new Uri(deets["Img"], UriKind.Relative));
        }

        public void btnOn() 
        {
            IsOn = true;
            FixBtnBk.Fill = bkOn;
            FixBtnBk.Stroke = dotOn;
            FixBtnDot.Fill = dotOn;
            FixBtnDot.Margin = btnDotOn;
        }
        public void btnOff() 
        {
            IsOn = false;
            FixBtnBk.Fill = bkOff;
            FixBtnBk.Stroke = dotOff;
            FixBtnDot.Fill = dotOff;
            FixBtnDot.Margin = btnDotOff;
        }

        private void FixBtnBk_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //if (isOn)
            //{
            //  btnOff();
            //}
            //else
            //{
            //  btnOn();
            //}
        }
        private void FixBtnDot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            FixBtnBk_MouseLeftButtonDown(sender, e);
        }

    }

I've commented out the click events for now so I can try to trigger the same effect from outside:我现在已经注释掉了点击事件,所以我可以尝试从外部触发相同的效果:

        // The click event I'm trying to build
        private void fixClick(object sender, EventArgs e)
        {
            StatusBox.Text = "CLICK WORKS";
            FixerBox whichFix = (FixerBox)sender;
            if (whichFix.IsOn)
            {
                whichFix.btnOff();
            }
            else
            {
                whichFix.btnOn();
            }
        }

        // The constructor of my app
        public MainWindow()
        {
            InitializeComponent();
            // fixNames is a dictionary containing details of each control
            var fixNames = fixers.FixerNames();
            foreach (string key in fixNames)
            {
                var temp = fixers.GetFix(key);
                // Be sure to pass this along as well
                temp["Name"] = key;
                fixerBoxes[key] = new FixerBox(temp);
                fixerBoxes[key].FindName("FixBtnBk") = new EventHandler(fixClick);
                FixersArea.Children.Add(fixerBoxes[key]);
            }           
        }

Above is my main app constructor where I generate all the controls.上面是我的主要应用程序构造函数,我在其中生成所有控件。 The issue is that on the line where I'm setting the event handler, I can't figure out how to actually make it work.问题是在我设置事件处理程序的那一行,我无法弄清楚如何让它真正起作用。 FindName should get the specific control, but it doesn't HAVE a click event or mousedown or anything. FindName 应该获得特定的控件,但它没有单击事件或鼠标按下或任何东西。 How can I attach my custom click event to each control?如何将我的自定义点击事件附加到每个控件?

The reason I'm doing it this way is because along with toggling the button, I want it to actually make system changes and registry updates in response to which control was clicked.我这样做的原因是因为随着切换按钮,我希望它实际进行系统更改和注册表更新以响应单击哪个控件。 I could keep all the responses in a class and include them in the custom control, but that seems sloppy both from a system resources viewpoint and a programming viewpoint.我可以将所有响应保留在 class 中,并将它们包含在自定义控件中,但从系统资源的角度和编程的角度来看,这似乎很草率。

Instead, if I can figure out how to access the various elements of the dynamic controls and add click events to them (or any equivalent workaround), that seems better.相反,如果我能弄清楚如何访问动态控件的各种元素并向它们添加单击事件(或任何等效的解决方法),那似乎更好。

how do I access elements of dynamically generated controls or otherwise add click events to them.如何访问动态生成的控件的元素或以其他方式向它们添加点击事件。 What I'm trying to do is figure out how to bring the "onclick" logic out of the control and into the main file so I can properly respond to it.我想做的是弄清楚如何将“onclick”逻辑从控件中移出并放入主文件中,以便我可以正确地响应它。

As mentioned in my comments above, you could create public events that you could subscribe to and respond to those events as needed.正如我在上面的评论中提到的,您可以创建您可以订阅的公共事件,并根据需要响应这些事件。

In your FixerBox class:在你的FixerBox class 中:

  • Add event: public event RoutedEventHandler MouseLeftBtnDown;添加事件: public event RoutedEventHandler MouseLeftBtnDown;

  • Invoke the event when needed:在需要时调用事件:

     private void FixerBox_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { MouseLeftBtnDown?.Invoke(this, new RoutedEventArgs()); }

In your class you want to subscribe to this new event:在您的 class 中,您想订阅这个新活动:

foreach (string key in fixNames)
            {
                var temp = fixers.GetFix(key);
                // Be sure to pass this along as well
                temp["Name"] = key;
                fixerBoxes[key] = new FixerBox(temp);
                fixerBoxes[key].MouseLeftBtnDown += fixClick;
                FixersArea.Children.Add(fixerBoxes[key]);
            }  

Your routine signature would need to be changed as well:您的常规签名也需要更改:

 private void fixClick(object sender, RoutedEventArgs e)

This should get you started, if you have questions please let me know.这应该可以帮助您入门,如果您有任何疑问,请告诉我。

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

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