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

时间:2017-01-18 12:34:27

标签: c# wpf

我正在尝试将事件处理程序添加到通过XamlReader创建的DataGridTemplateColumn中的RadioButtons。 这是我正在使用的代码:

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的原因是列中所需的RadioButton数量会有所不同,因此,我需要能够动态更改创建的RadioButtons数量。

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

作为旁注,只需在radioButtonString中添加“Checked ='rb_Checked'”就会抛出XamlParserException,因为XamlReader无法处理事件处理程序。

对此的任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:1)

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

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

如果您对使用应用于所有RadioButton的隐式Style不满意,可以执行以下操作。

创建一个继承自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);
}

请注意,您必须更改&#34; assembly = WpfApplication2&#34;到您定义MyDataGridTemplateColumn类的程序集的名称。这同样适用于命名空间。

答案 1 :(得分:0)

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

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

事件处理程序方法:

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

这将为RadioButton中的每个DataGrid调用处理程序。

答案 2 :(得分:0)

如果我没记错的话,可以在XAML中添加Checked =“CheckHandlerFunction”。这可能有用。

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