2014-11-04 22 views
0

我有以下數據網格WPF使用相同的DataTemplate不同的結合

<Window 
    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" mc:Ignorable="d" x:Class="VenusProductInfoQueryWPF.MainWindow" 
    Height="350" Width="646" WindowStyle="None" ResizeMode="NoResize" Topmost="False" MouseLeftButtonDown="Window_MouseLeftButtonDown" AllowsTransparency="True" WindowStartupLocation="CenterScreen" ShowInTaskbar="True"> 
    <Window.Resources>   
     <DataTemplate x:Key="DataTemplate1"> 
      <Button Tag="{Binding Name}" Content="Show" Click="LinkButton_Click"></Button> 
     </DataTemplate> 
     <DataTemplate x:Key="DataTemplate2"> 
      <Button Tag="{Binding Sex}" Content="Show" Click="LinkButton_Click"></Button> 
     </DataTemplate> 
    </Window.Resources>` 

    <Grid> 
     <DataGrid x:Name="MyDataGrid" HorizontalAlignment="Left" Margin="60,44,0,0" 
        VerticalAlignment="Top" Height="223" Width="402" AutoGenerateColumns="False" 
        AutoGeneratedColumns="MyDataGrid_AutoGeneratedColumns"> 
      <DataGrid.Columns> 
       <DataGridTextColumn Header="Age" Binding="{Binding Path=Age}"></DataGridTextColumn> 
       <DataGridTemplateColumn Header="Sex" CellTemplate="{StaticResource DataTemplate2}"/> 
       <DataGridTemplateColumn Header="Name" CellTemplate="{StaticResource DataTemplate1}"/> 
      </DataGrid.Columns> 
     </DataGrid> 
    </Grid> 
</Window> 

,並在代碼隱藏我:

using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Windows; 
using System.Windows.Media; 

namespace WpfApplication1 
{ 
public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     dataSource = new DataTable(); 
     dataSource.Columns.Add("Age"); 
     dataSource.Columns.Add("Name"); 
     dataSource.Columns.Add("Sex"); 

     AddNewRow(new object[] { 10, "wang", "Male" }); 
     AddNewRow(new object[] { 15, "huang", "Male" }); 
     AddNewRow(new object[] { 20, "gao", "Female" }); 

     dataGrid1.ItemsSource = dataSource.AsDataView(); 
    } 
} 
} 

DataTable中有超過30列(我只在這裏寫下2使問題變得更容易)。問題是:如果我想要在每一列中顯示與不同數據源相同的模板樣式,是否真的必須定義許多不同的數據模板(如DataTemplate1,DataTemplate2,...參見上文)將每個DataGridTemplateColumn的CellTemplate綁定到它?我可以定義一個數據模板,並在代碼中或通過其他方式動態設置綁定?謝謝您的回答!

+0

每個按鈕都有自己與相應屬性的綁定,所以我不認爲有一些方法可以在這裏使用1個模板。雖然我們可以縮短你的模板,就像這樣:

回答

0

有一種方式,但它是不漂亮,

爲了簡便起見,我使用的代碼背後的視圖模型,我已刪除了異常處理和不必要的行。

我有你的對象數組轉換成Person對象(對於應在解決方案後變得明顯的原因)

public class Person 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 
    public string Sex { get; set; } 
} 

我已經將您的數據源到一個ObservableCollection這樣的代碼背後,是現在

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     Items = new ObservableCollection<Person>() 
     { 
      new Person {Age = 10, Name = "wang", Sex="Male"}, 
      new Person {Age = 15, Name = "huang", Sex="Male"}, 
      new Person {Age = 20, Name = "gao", Sex="Female"} 
     }; 
     ShowCommand = new DelegateCommand(ExecuteShowCommand, CanExecuteShowCommand); 
     InitializeComponent(); 
    } 

    private bool CanExecuteShowCommand(object arg) { return true; } 
    private void ExecuteShowCommand(object obj) { MessageBox.Show(obj != null ? obj.ToString() : "No Parameter received"); } 
    public DelegateCommand ShowCommand { get; set; } 
    public ObservableCollection<Person> Items { get; set; } 
} 

的DelegateCommand被定義爲

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

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

    public bool CanExecute(object parameter) { return _canExecute.Invoke(parameter); } 
    void ICommand.Execute(object parameter) { _execute.Invoke(parameter); } 
    public event EventHandler CanExecuteChanged; 
} 

這允許在單個模板中使用Commands和CommandParameters。

然後,使用一個MultiValueConverter獲取數據爲每個按鈕。它使用列的標題來查詢使用反射的Person對象以獲取所需的值,然後將其作爲命令的參數傳回。

public class GridCellToValueConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     object returnValue = null; 
     var person = values.First() as Person; 
     var propertyName = values[1] == DependencyProperty.UnsetValue ? string.Empty : (string)values[1]; 
     if ((person != null) && (!string.IsNullOrWhiteSpace(propertyName))) { returnValue = person.GetType().GetProperty(propertyName).GetValue(person); } 
     return returnValue; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } 
} 

的最後一塊拼圖是XAML

<Window x:Class="StackOverflow.Q26731995.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:q26731995="clr-namespace:StackOverflow.Q26731995" Title="MainWindow" Height="350" Width="525" 
     DataContext="{Binding RelativeSource={RelativeSource Self}}"> 
    <Window.Resources> 
     <q26731995:GridCellToValueConverter x:Key="GridCell2Value" /> 
     <DataTemplate x:Key="ButtonColumnDataTemplate"> 
      <Button Content="Show" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=ShowCommand}"> 
       <Button.CommandParameter> 
        <MultiBinding Converter="{StaticResource GridCell2Value}"> 
         <Binding /> <!-- The person object --> 
         <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridCell}}" Path="Column.Header" /> <!-- The name of the field --> 
        </MultiBinding> 
       </Button.CommandParameter> 
      </Button> 
     </DataTemplate> 
    </Window.Resources> 

    <Grid> 
     <DataGrid x:Name="MyDataGrid" HorizontalAlignment="Left" Margin="60,44,0,0" ItemsSource="{Binding Path=Items}" VerticalAlignment="Top" Height="223" Width="402" AutoGenerateColumns="False"> 
      <DataGrid.Columns> 
       <DataGridTextColumn Header="Age" Binding="{Binding Path=Age}"></DataGridTextColumn> 
       <DataGridTemplateColumn Header="Sex" CellTemplate="{StaticResource ButtonColumnDataTemplate}"/> 
       <DataGridTemplateColumn Header="Name" CellTemplate="{StaticResource ButtonColumnDataTemplate}"/> 
      </DataGrid.Columns> 
     </DataGrid> 
    </Grid> 
</Window> 

你應該能夠削減和過去的這個代碼到一個新的WPF應用程序,看看它的工作。不是我沒有照顧網格添加的AddNewItem行(因爲我們沒有關閉它)。

這可以通過對象數組的集合,而不是人的集合來完成。爲此,您需要將DataGridCellsPanel傳遞給轉換器,並將其與標題一起使用以計算所需值的索引。轉換看起來像

<MultiBinding Converter="{StaticResource GridCell2Value}"> 
    <Binding /> <!-- The data --> 
    <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridCell}}" Path="Column.Header}" /> <!-- The name of the field --> 
    <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridCellsPanel}}" /> <!-- The panel that contains the row --> 
</MultiBinding> 

轉換器代碼將是沿線

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     object returnValue = null; 

     var data = values.First() as object[]; 
     var property = values[1] == DependencyProperty.UnsetValue ? string.Empty : (string)values[1]; 
     var panel = values[2] as DataGridCellsPanel; 
     var column = panel.Children.OfType<DataGridCell>().FirstOrDefault(c => c.Column.Header.Equals(property)); 
     if (column != null) 
     { 
      returnValue = data[panel.Children.IndexOf(column)]; 
     } 
     return returnValue; 
    } 

我希望這有助於。

+0

謝謝,我現在專注於其他項目,我會盡快嘗試您的代碼。 – DayongWang 2014-11-10 02:01:00

相關問題