2016-03-02 124 views
1

我尝试通过代码动态创建并将DataTemplate指定给HeaderTemplateDataGrid。为此,我有一个方法GetDatatemplate(string fromstring),它定义了一个XML文字,然后用它来创建一个DataTemplate。只要我不在DataTemplate中包含MouseLeftButtonDown事件处理程序,这工作正常。如何在代码中为DataTemplate分配事件处理程序?

DataTemplate保存在string变量的代码隐藏称为StringHeaderTemplateMainWindow.xaml.cs

private string StringHeaderTemplate [email protected]"<DataTemplate> 
    <DataTemplate.Resources>     
     <ControlTemplate x:Key=""imgNo"" TargetType=""{x:Type Control}""> 
     <Image Source = ""pack://application:,,,/Images/upArrow.png"" /> 
     </ControlTemplate > 
     <ControlTemplate x:Key=""imgUp"" TargetType=""{x:Type Control}""> 
     <Image Source = ""pack://application:,,,/Images/upArrow.png"" /> 
     </ControlTemplate > 
     <ControlTemplate x:Key=""imgDown"" TargetType=""{x:Type Control}"" > 
     <Image Source = ""pack://application:,,,/Images/downArrow.png"" /> 
     </ControlTemplate > 
    </DataTemplate.Resources> 
    <Grid Background=""Transparent"" MouseLeftButtonDown=""Grid_MouseLeftButtonDown""> 
     <Grid.RowDefinitions> 
      <RowDefinition/> 
      <RowDefinition/> 
      <RowDefinition/> 
     </Grid.RowDefinitions> 
     <Button Content=""Hello""/> 
     <TextBlock Grid.Row=""1"" HorizontalAlignment= ""Center"" Text = ""TextBlock"" /> 
     <CheckBox Grid.Row= ""2"" HorizontalAlignment= ""Center"" IsChecked= ""True"" /> 
    </Grid >  
</DataTemplate>"; 

和获取方法DataTemplate

private DataTemplate GetDatatemplate(string fromstring) 
{ 
    ParserContext context = new ParserContext(); 
    context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation"); 
    context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml"); 
    return (DataTemplate)XamlReader.Parse(fromstring, context); 
} 

然后我申请HeaderTemplateDataGrid这个DataTemplate到:

private void dg_AutoGeneratingColumn_1(object sender, DataGridAutoGeneratingColumnEventArgs e) 
{ 
    DataTemplate dtCell = null; 
    DataTemplate dtHeader = null; 
    string dtString = string.Empty; 
    string dtHeaderString = string.Empty; 
    switch(Type.GetTypeCode(e.PropertyType)) 
    { 
     case TypeCode.String: 
     dtString = StringTemplate.Replace("xxColumnxx", e.PropertyName); 
     dtHeaderString=StringHeaderTemplate; 
     break; 
    } 
    if(!string.IsNullOrEmpty(dtString)) 
    { 
     dtCell = GetDataTemplateForDataGrid(dtCellString); 
     dtHeader = GetDataTemplateForDataGrid(dtHeaderString); 
     DataGridTemplateColumn c = new DataGridTemplateColumn() 
     { 
      CellTemplate = dtCell, 
      HeaderTemplate = dtHeader, 
     }; 
     e.Column = c;    
    } 
} 

事件处理程序是非常简单的:

private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
{ 
    MessageBox.Show(DateTime.Now.ToString());   
} 

的例外,我得到的是有一个类型的ArgumentException的的InnerException,上面写着一个XamlParseException:

“无法绑定到目标的方法,因为其签名或安全性 透明度与委托类型不兼容。“

任何想法该怎么办?

更新:

我试图通过Command绑定,但是CallSortingCommand不叫。也许你知道我做错了什么?

<Grid Background=""Transparent""> 
    <i:Interaction.Triggers>     
     <i:EventTrigger EventName=""MouseLeftButtonDown"">           
      <prism:InvokeCommandAction Command = ""{Binding 
      RelativeSource={RelativeSource AncestorType=Window, 
      Mode=FindAncestor}, Path=DataContext.CallSortingCommand}"" /> 
     </i:EventTrigger>    
    </i:Interaction.Triggers>    
    <Grid.RowDefinitions> 
     <RowDefinition/> 
     <RowDefinition/> 
     <RowDefinition/> 
    </Grid.RowDefinitions> 
    <Button Content=""Hello""/> 
    <TextBlock Grid.Row=""1"" HorizontalAlignment= ""Center"" Text = ""TextBlock"" /> 
    CheckBox Grid.Row= ""2"" HorizontalAlignment= ""Center"" IsChecked= ""True"" /> 
</Grid > 
+0

什么StringTemplate的? –

+0

'private string StringHeaderTemplate = @'omg stop right there ...你在做什么?DataTemplates应该在你的资源中定义。如果你需要自定义逻辑来选择一个数据模板,创建并使用一个DataTemplateSelector 。怎么回事我连 – Will

回答

2

这是一个有趣的问题,'因为可能的解决方案可能是在应用数据模板之后找到想要在可视树中订阅的对象。但是这是一个专栏,在这种情况下很难访问可视化树。

我建议使用Interactions,它允许在XAML中定义事件触发器。请看下面的代码:

private string StringHeaderTemplate = @"<DataTemplate> 
    <Grid Background=""Transparent""> 
     <i:Interaction.Triggers> 
     <i:EventTrigger EventName=""MouseLeftButtonDown""> 
      <si:CallMethodAction MethodName = ""Grid_MouseLeftButtonDown"" TargetObject=""{Binding RelativeSource={RelativeSource AncestorType=Window}}""/> 
     </i:EventTrigger> 
     </i:Interaction.Triggers> 
     <Grid.RowDefinitions> 
      <RowDefinition/> 
      <RowDefinition/> 
      <RowDefinition/> 
     </Grid.RowDefinitions> 
     <Button Content=""Hello""/> 
     <TextBlock Grid.Row=""1"" HorizontalAlignment= ""Center"" Text = ""TextBlock"" /> 
     <CheckBox Grid.Row= ""2"" HorizontalAlignment= ""Center"" IsChecked= ""True"" /> 
    </Grid >  
</DataTemplate>"; 


    public void Grid_MouseLeftButtonDown(object sender, RoutedEventArgs e) 
    { 
     MessageBox.Show(DateTime.Now.ToString()); 
    } 

    private DataTemplate GetDatatemplate(string fromstring) 
    { 
     ParserContext context = new ParserContext(); 
     context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation"); 
     context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml"); 
     context.XmlnsDictionary.Add("i", "clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"); 
     context.XmlnsDictionary.Add("si", "clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"); 

     return (DataTemplate)XamlReader.Parse(fromstring, context); 
    } 

P.S.请注意Grid_MouseLeftButtonDown事件处理程序的公共访问修饰符,私有它不起作用。

UPDATE

完整的源代码:

XAML

<Window x:Class="DataGridDataTemplateInCode.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:DataGridDataTemplateInCode" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <DataGrid Name="dg" ItemsSource="{Binding Items}" AutoGeneratingColumn="dg_AutoGeneratingColumn" /> 
    </Grid> 
</Window> 

C#

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

     DataContext = new MainWindowViewModel(); 
    } 


    private string StringHeaderTemplate = @"<DataTemplate> 
    <Grid Background=""Transparent""> 
     <i:Interaction.Triggers> 
     <i:EventTrigger EventName=""PreviewMouseLeftButtonDown"">    
      <si:CallMethodAction MethodName = ""Grid_MouseLeftButtonDown"" TargetObject=""{Binding RelativeSource={RelativeSource AncestorType=Window}}""/> 
     </i:EventTrigger> 
     </i:Interaction.Triggers> 
     <Grid.RowDefinitions> 
      <RowDefinition/> 
      <RowDefinition/> 
      <RowDefinition/> 
     </Grid.RowDefinitions> 
     <Button Content=""Hello""/> 
     <TextBlock Grid.Row=""1"" HorizontalAlignment= ""Center"" Text = ""Grid_MouseLeftButtonDown"" /> 
     <CheckBox Grid.Row= ""2"" HorizontalAlignment= ""Center"" IsChecked= ""True"" /> 
    </Grid >  
</DataTemplate>"; 


    private string DateTimeWithCommandHeaderTemplate = @"<DataTemplate> 
    <Grid Background=""Transparent""> 
     <i:Interaction.Triggers> 
     <i:EventTrigger EventName=""MouseLeftButtonDown"">    
      <i:InvokeCommandAction Command = ""{Binding DataContext.CallSortingCommand, RelativeSource={RelativeSource AncestorType=Window}}""/> 
     </i:EventTrigger> 
     </i:Interaction.Triggers> 
     <Grid.RowDefinitions> 
      <RowDefinition/> 
      <RowDefinition/> 
      <RowDefinition/> 
     </Grid.RowDefinitions> 
     <Button Content=""Hello""/> 
     <TextBlock Grid.Row=""1"" HorizontalAlignment= ""Center"" Text = ""CallSortingCommand"" /> 
     <CheckBox Grid.Row= ""2"" HorizontalAlignment= ""Center"" IsChecked= ""True"" /> 
    </Grid >  
</DataTemplate>"; 

    private string TimeCellTemplate = @"<DataTemplate> 
     <TextBlock HorizontalAlignment= ""Center"" Text = ""{Binding Time}"" /> 
</DataTemplate>"; 

    private string DescCellTemplate = @"<DataTemplate> 
     <TextBlock HorizontalAlignment= ""Center"" Text = ""{Binding Desc}"" /> 
</DataTemplate>"; 


    public void Grid_MouseLeftButtonDown(object sender, RoutedEventArgs e) 
    { 
     //MessageBox.Show(DateTime.Now.ToString()); 

     var vm = DataContext as MainWindowViewModel; 

     vm.Items[0].Desc += "+"; 
    } 

    private DataTemplate GetDatatemplate(string fromstring) 
    { 
     ParserContext context = new ParserContext(); 
     context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation"); 
     context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml"); 
     context.XmlnsDictionary.Add("i", "clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"); 
     context.XmlnsDictionary.Add("si", "clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"); 

     return (DataTemplate)XamlReader.Parse(fromstring, context); 
    } 

    private void dg_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) 
    { 
     DataTemplate dtHeader = null; 
     string dtString = string.Empty; 
     string dtHeaderString = string.Empty; 

     DataGridTemplateColumn column = null; 

     switch (Type.GetTypeCode(e.PropertyType)) 
     { 
      case TypeCode.String: 
       { 
        column = new DataGridTemplateColumn() 
        { 
         CellTemplate = GetDatatemplate(DescCellTemplate), 
         HeaderTemplate = GetDatatemplate(StringHeaderTemplate), 
        }; 
       } 

       break; 

      case TypeCode.DateTime: 
       { 
        column = new DataGridTemplateColumn() 
        { 
         CellTemplate = GetDatatemplate(TimeCellTemplate), 
         HeaderTemplate = GetDatatemplate(DateTimeWithCommandHeaderTemplate), 
        }; 
       } 

       break; 
     } 

     if (column != null) 
     { 
      e.Column = column; 
     } 
    } 
} 

public class MainWindowViewModel : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public MainWindowViewModel() 
    { 

     for (int i = 0; i < 10; i++) 
     { 
      _collection.Add(new MyObject() { Time = DateTime.Now.AddSeconds(i), Desc = i.ToString() }); 
     } 

     CallSortingCommand = new DelegateCommand(OnCallSortingCommand, (o) => true); 
    } 

    private void OnCallSortingCommand(object obj) 
    { 
     MessageBox.Show("From OnCallSortingCommand"); 
    } 

    public ICommand CallSortingCommand { get; set; } 


    private ObservableCollection<MyObject> _collection = new ObservableCollection<MyObject>(); 
    public ObservableCollection<MyObject> Items 
    { 
     get 
     { 
      return _collection; 
     } 
    } 


    protected void OnPropertyChanged([CallerMemberName] string property = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property)); 
    }  
} 


public class MyObject : INotifyPropertyChanged 
{ 
    public DateTime Time { get; set; } 


    private string _desc; 

    public string Desc 
    { 
     get { return _desc; } 
     set { _desc = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Desc))); } 
    } 


    public event PropertyChangedEventHandler PropertyChanged; 
} 



public class DelegateCommand : ICommand 
{ 
    private readonly Action<object> _execute; 
    private readonly Func<object, bool> _canExecute; 

    public event EventHandler CanExecuteChanged; 


    public DelegateCommand(Action<object> execute, Func<object, bool> canExecute) 
    { 
     _execute = execute; 
     _canExecute = canExecute; 
    } 

    public bool CanExecute(object parameter) 
    { 
     return _canExecute(parameter); 
    } 

    public void Execute(object parameter) 
    { 
     _execute(parameter); 
    } 
} 
+0

都没有,谢谢,安东,我会试试看。你能不能建议阅读一些关于'DataContext'和'Visual Tree'之间的连接的文章?我觉得这是非常重要的领域。 – StepUp

+0

谢谢,安东,我已经尝试过这种方法,但它不会触发'public void Grid_MouseLeftButtonDown(object sender,RoutedEventArgs e)' – StepUp

+0

此外,我试过使用'Command'(** Update **部分的问题)然而,'CallSortingCommand'没有被触发 – StepUp

相关问题