C# 如何以编程方式将事件处理程序添加到使用XamlReader动态创建的DataGridTemplateColumn中的单选按钮?

C# 如何以编程方式将事件处理程序添加到使用XamlReader动态创建的DataGridTemplateColumn中的单选按钮?,c#,wpf,C#,Wpf,我正在尝试向DataGridTemplateColumn中的单选按钮添加事件处理程序,该列是通过XamlReader创建的。 以下是我正在使用的代码: string templateColumnStart = @"<DataGridTemplateColumn Header='Svar' Width='200' x:Name='myTemplateColumn' xmlns ='http://schemas.microsoft.com/winfx/2006/xaml/present

我正在尝试向DataGridTemplateColumn中的单选按钮添加事件处理程序,该列是通过XamlReader创建的。 以下是我正在使用的代码:

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);
我使用XamlReader创建TemplateColumn的原因是该列中所需的单选按钮的数量会有所不同,因此,我需要能够动态更改所创建的单选按钮的数量

创建列并将其添加到DataGrid时没有问题,并且RadioButton显示正确。但是,似乎没有添加事件处理程序,因为检查按钮不会触发它

作为旁注,简单地将Checked='rb_Checked'添加到radioButtonString会引发XamlParserException,因为XamlReader无法处理事件处理程序

如果您有任何帮助,我们将不胜感激。

您可以将EventSetter添加到您的窗口,如下所示:

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

这将调用DataGrid中每个单选按钮的处理程序。

如果我没记错,您可以在XAML本身中添加Checked=CheckHandlerFunction。这可能行得通


这可能不适用于您的情况,但您是否研究过模板和将控件绑定到DataContext?您可以使用它们在WPF中自动创建大量控件。

这里的主要问题是您将事件处理程序连接到错误的RadioButton实例。当应用CellTemplate时,WPF运行时将创建一个新的方法,因此在这里调用LoadContent方法毫无意义

不幸的是,DataGridColumn类在调用GenerateElement方法时不会引发任何事件,因此您必须创建自己的自定义DataGridColumn,以便在实际应用模板后获得对StackPanel的引用。在此之前,没有StackPanel或RadioButton。DataTemplate顾名思义就是最终应用的模板

如果您对使用应用于所有单选按钮的隐式样式不满意,可以这样做

创建从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 });
        }
    }
}
并稍微修改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);
}

请注意,必须将assembly=WpfApplication2更改为定义MyDataGridTemplateColumn类的程序集的名称。名称空间也是如此。

提问时,请记住,如果答案适合您,请将其标记为已接受:
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);
}