简体   繁体   English

如何以编程方式将事件处理程序添加到使用XamlReader动态创建的DataGridTemplateColumn中的RadioButtons中?

[英]How do I programmatically add event handlers to RadioButtons in a DataGridTemplateColumn that is dynamically created using XamlReader?

I am trying to add event handlers to RadioButtons in a DataGridTemplateColumn which is created through XamlReader. 我试图将事件处理程序添加到通过XamlReader创建的DataGridTemplateColumn中的RadioButtons中。 Here is the code I'm using: 这是我正在使用的代码:

string templateColumnStart = @"<DataGridTemplateColumn Header='Svar' Width='200' x:Name='myTemplateColumn'
    xmlns ='http://schemas.microsoft.com/winfx/2006/xaml/presentation' 
    xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <StackPanel Orientation='Horizontal'>";
string templateColumnEnd = @"</StackPanel>
    </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>";
string radioButtonString = @"<RadioButton Name='rb1' Content='1' IsChecked='false'/>";
string fullXamlString = templateColumnStart + radioButtonString + templateColumnEnd;
MemoryStream stream = new MemoryStream(ASCIIEncoding.UTF8.GetBytes(fullXamlString));
DataGridTemplateColumn templateColumn = (DataGridTemplateColumn)XamlReader.Load(stream);
StackPanel template = (StackPanel)templateColumn.CellTemplate.LoadContent();
RadioButton radiobutton = (RadioButton)template.FindName("rb1");
radiobutton.Checked += new RoutedEventHandler(rb_Checked);
myDataGrid.Columns.Add(templateColumn);

The reason I'm using XamlReader to create the TemplateColumn is that the number of RadioButtons needed in the column will vary, and as such, I need the ability to dynamically change the number of RadioButtons created. 我使用XamlReader创建TemplateColumn的原因是,该列中所需的RadioButtons数量会有所不同,因此,我需要能够动态更改创建的RadioButtons的数量。

The column is created and added to the DataGrid without a problem, and the RadioButton is displayed correctly. 创建该列并将其毫无问题地添加到DataGrid,并且RadioButton可以正确显示。 However, the event handler does not seem to have been added, as checking the button does not trigger it. 但是,似乎未添加事件处理程序,因为检查按钮不会触发它。

As a side note, simply adding "Checked='rb_Checked'" to the radioButtonString throws a XamlParserException, as XamlReader is not able to handle event handlers. 附带说明一下,仅将“ Checked ='rb_Checked'”添加到radioButtonString会引发XamlParserException,因为XamlReader无法处理事件处理程序。

Any help with this would be greatly appreciated. 任何帮助,将不胜感激。

The main issue here is that you are hooking up the event handler to the wrong RadioButton instance. 这里的主要问题是您将事件处理程序连接到错误的RadioButton实例。 A new one will be created by the WPF runtime when the CellTemplate is applied so calling the LoadContent() method is meaningless here. 当应用CellTemplate时,WPF运行时将创建一个新对象,因此在这里调用LoadContent()方法是没有意义的。

Unfortunately the DataGridColumn class doesn't raise any events when the GenerateElement method is invoked so you will have to create your own custom DataGridColumn to be able to get a reference to the StackPanel once the template has actually been applied. 不幸的是,当调用GenerateElement方法时,DataGridColumn类不会引发任何事件,因此一旦模板被实际应用,您将必须创建自己的自定义DataGridColumn才能获得对StackPanel的引用。 Before this there is no StackPanel nor RadioButton. 在此之前,没有StackPanel或RadioButton。 A DataTemplate is as the name implies just a template that is being applied eventually . 顾名思义,DataTemplate只是一个最终要应用的模板

Here is what you could do if you are not satisfied with using an implicit Style that gets applied to all RadioButtons. 如果您不满意使用适用于所有RadioButton的隐式样式,可以执行以下操作。

Create a custom class that inherits from DataGridTemplateColumn and raises an event when the GenerateElement method is called: 创建一个自定义类,该类继承自DataGridTemplateColumn,并在调用GenerateElement方法时引发一个事件:

namespace WpfApplication2
{
    public class CellElementGeneratedEventArgs : EventArgs
    {
        public FrameworkElement Content { get; set; }
    }

    public delegate void CellElementGeneratedEventHandler(object sender, CellElementGeneratedEventArgs e);

    public class MyDataGridTemplateColumn : DataGridTemplateColumn
    {
        public event CellElementGeneratedEventHandler ElementGenerated;

        protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
        {
            FrameworkElement fe = base.GenerateElement(cell, dataItem);
            if(fe != null)
                fe.Loaded += Fe_Loaded;
            return fe;
        }

        private void Fe_Loaded(object sender, RoutedEventArgs e)
        {
            if (ElementGenerated != null)
                ElementGenerated(this, new CellElementGeneratedEventArgs() { Content = sender as FrameworkElement });
        }
    }
}

And modify your XAML markup and code slightly: 并稍微修改您的XAML标记和代码:

string templateColumnStart = @"<local:MyDataGridTemplateColumn Header='Svar' Width='200' x:Name='myTemplateColumn' xmlns ='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' xmlns:local='clr-namespace:WpfApplication2;assembly=WpfApplication2'> <DataGridTemplateColumn.CellTemplate><DataTemplate><StackPanel Orientation='Horizontal'>";
string templateColumnEnd = @"</StackPanel></DataTemplate></DataGridTemplateColumn.CellTemplate></local:MyDataGridTemplateColumn>";
string radioButtonString = @"<RadioButton Name='rb1' Content='1' IsChecked='false'/>";
string fullXamlString = templateColumnStart + radioButtonString + templateColumnEnd;
using (MemoryStream stream = new MemoryStream(ASCIIEncoding.UTF8.GetBytes(fullXamlString)))
{
    MyDataGridTemplateColumn templateColumn = (MyDataGridTemplateColumn)XamlReader.Load(stream);
    templateColumn.ElementGenerated += (ss, ee) => 
    {
        ContentPresenter cc = ee.Content as ContentPresenter;
        if(cc != null)
        {
            StackPanel sp = VisualTreeHelper.GetChild(cc, 0) as StackPanel;
            if(sp != null)
            {
                RadioButton rb = sp.FindName("rb1") as RadioButton;
                if (rb != null)
                    rb.Checked += rb_Checked;
            }
        }
    };
    myDataGrid.Columns.Add(templateColumn);
}

Note that the you will have to change "assembly=WpfApplication2" to the name of the assembly where you define your MyDataGridTemplateColumn class. 请注意,您必须将“ assembly = WpfApplication2”更改为定义MyDataGridTemplateColumn类的程序集的名称。 The same applies to the namespace. 命名空间也是如此。

You can add EventSetter to your window like this: 您可以像这样将EventSetter添加到窗口中:

<Window.Resources>
    <Style TargetType="{x:Type RadioButton}">
        <EventSetter Event="Checked" Handler="RadioButton_Checked"/>
    </Style>
</Window.Resources>

Event handler method: 事件处理程序方法:

void RadioButton_Checked(object sender, RoutedEventArgs e)
{
   // Handle the event...
}

This will call the handler for every RadioButton in your DataGrid . 这将为DataGrid每个RadioButton调用处理程序。

If I remember correctly, you can add Checked="CheckHandlerFunction" in the XAML itself. 如果我没记错的话,可以在XAML本身中添加Checked =“ CheckHandlerFunction”。 That may work. 那可能行得通。

This may not apply in your situation, but have you looked into templates and binding controls to DataContext? 这可能不适用于您的情况,但是您是否研究过模板以及将控件绑定到DataContext的方法? You can automate a lot of control creation in WPF using them. 您可以使用它们在WPF中自动执行很多控件创建。

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

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