2014-11-04 5 views
0

바인딩과 같은 DataTemplate을를 사용하는 I가 다음과 같은 데이터 그리드WPF는 다른이

<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에 (나는 단지 여기에 2를 쓴 30 개 이상의 열이 따라야 쉽게) .. 질문 : 모든 열에 서로 다른 빙싱 소스가있는 동일한 템플릿 스타일을 표시하려면 실제로 많은 다른 데이터 템플릿을 정의해야합니까 (예 : DataTemplate1, DataTemplate2 ...)) 각 DataGridTemplateColumn의 CellTemplate을 바인딩하려면? 하나의 데이터 템플릿을 정의하고 코드에서 또는 다른 방법으로 바인딩을 동적으로 설정할 수 있습니까? 답변 주셔서 감사합니다! 간결함을 위해

+0

각 버튼마다 해당 속성이있는 바인딩이 있으므로 여기에 1 개의 템플릿 만 사용하는 방법이 있다고 생각하지 않습니다. 템플릿을 이렇게 짧게 만들 수는 있지만,

답변

0

이있는 방법이지만 꽤 아니라,

내가보기 모델로 뒤에 코드를 사용하고 난 예외 처리와 불필요한 라인을 제거했습니다.

코드 뒤에 지금

이다 그래서 나는

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

은 내가 ObservableCollection에로 데이터 소스를 변환 한 (용액에 나중에 분명하게해야한다 이유로) Person 객체로 객체 배열을 변환해야

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; 
} 
,536로 정의

이렇게하면 단일 템플리트에서 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(); } 
} 

퍼즐의 마지막 조각은 새로운 WPF 응용 프로그램으로 당신은 절단 할 수 있어야한다 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> 

이 코드를지나이며 작동을 참조하십시오. 그리드가 추가하는 AddNewItem 행을 처리하지 않았습니다 (우리가이 기능을 해제하지 않았으므로).

이 작업은 Person 컬렉션이 아닌 객체 배열 컬렉션을 사용하여 수행 할 수 있습니다. 이렇게하려면 DataGridCellsPanel을 변환기에 전달하고 헤더와 함께 사용하여 필요한 값의 인덱스를 계산해야합니다. 변환기 코드는 선 난이 도움이되기를 바랍니다

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; 
    } 

함께 할 것

<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> 

처럼 변환이 보일 것이다.

+0

고마워, 요즘 다른 프로젝트에 초점을 맞추었고 곧 코드를 시험해 보겠습니다. – DayongWang