2013-07-27 110 views
4

我想定製 DataGridColumnHeader顯示多個文本字段,而不是
僅表示 DataGridColumn.Header酒店所提供的標題文字。
如果我沒有錯過任何東西,我只需創建一個 DataTemplate並綁定到父對象的屬性
。這適用於 DataGridColumn.Header屬性,但
對附加屬性的綁定失敗。綁定DataGrid列DataTemplate中以附加屬性

爲了完整起見,執行附加屬性:

public static class CustomHeader 
{ 
    public static string GetUnit(DependencyObject obj) { return (string)obj.GetValue(UnitProperty); } 
    public static void SetUnit(DependencyObject obj, string value) { obj.SetValue(UnitProperty, value); } 

    public static readonly DependencyProperty UnitProperty = DependencyProperty.RegisterAttached(
     "Unit", typeof(string), typeof(CustomHeader), new FrameworkPropertyMetadata(null)); 
} 

在XAML的標記使用方法:

<DataGrid x:Name="tObjectDataGrid" Margin="10,50,10,10" 
        AutoGenerateColumns="False" EnableRowVirtualization="True" 
        ItemsSource="{Binding ObjectList}" 
        RowDetailsVisibilityMode="VisibleWhenSelected" > 
    <DataGrid.Resources> 
    <DataTemplate x:Key="CustomHeaderTemplate"> 
     <StackPanel> 
     <TextBlock Text="{Binding}" /> 
     <TextBlock Text="{Binding Path=(cust:CustomHeader.Unit)}" /> <-- attached binding doesn't work :( 
     </StackPanel> 
    </DataTemplate> 
    </DataGrid.Resources> 

    <DataGrid.Columns> 
    <DataGridTextColumn x:Name="SpeedColumn" 
         Width="1*" 
         Binding="{Binding Speed}" 
         Header="Speed" 
         HeaderTemplate="{StaticResource CustomHeaderTemplate}" 
         cust:CustomHeader.Unit="[m/s]" /> 
    </DataGrid.Columns> 
</DataGrid> 

我真的很感激任何意見或網絡鏈接來闡明我缺少什麼這裏。 在此先感謝。

+0

你在哪裏設置這個'附property'? –

+0

它在DataGridTextColumn的最後一行中設置... cust:CustomHeader.Unit =「[m/s]」。類'CustomHeader'位於與測試項目其餘部分相同的程序集(在一個測試項目中)和相同的名稱空間中。 「cust」是xmlns:cust =「clr-namespace:DependencyTest」(待完成)...這個設置是否可能會引入意想不到的副作用? – LaWi

+0

行爲是完全正確的,因爲您在'DataGridTextColumn'和'HeaderTemplate'上設置了附加屬性,而不是位於列的'Visual Tree'中。因此不會繼承附加屬性。如果您將屬性的默認值設置爲「TestString」,則該值將顯示在標題中。 –

回答

3

您應該使用多值轉換器(msdn)。

XAML:

<DataGrid x:Name="tObjectDataGrid" Margin="10,50,10,10" 
      AutoGenerateColumns="False" EnableRowVirtualization="True" 
      ItemsSource="{Binding ObjectList}" 
      RowDetailsVisibilityMode="VisibleWhenSelected" > 
    <DataGrid.Resources> 
     <cust:UnitConverter x:Key="unitCon" /> 
     <DataTemplate x:Key="CustomHeaderTemplate"> 
      <StackPanel> 
       <TextBlock Text="{Binding}" /> 
       <TextBlock> 
        <TextBlock.Text> 
         <MultiBinding Converter="{StaticResource unitCon}"> 
          <Binding Path="Columns" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGrid}" /> 
          <Binding Path="." /> 
         </MultiBinding> 
        </TextBlock.Text> 
       </TextBlock> 
      </StackPanel> 
     </DataTemplate> 
    </DataGrid.Resources> 

    <DataGrid.Columns> 
     <DataGridTextColumn x:Name="SpeedColumn" 
       Width="1*" 
       Binding="{Binding Speed}" 
       Header="Speed" 
       HeaderTemplate="{StaticResource CustomHeaderTemplate}" 
       cust:CustomHeader.Unit="[m/s]" /> 

     <DataGridTextColumn x:Name="SpeedColumn2" 
       Width="1*" 
       Binding="{Binding Speed2}" 
       Header="Speed2" 
       HeaderTemplate="{StaticResource CustomHeaderTemplate}" 
       cust:CustomHeader.Unit="[km/h]" /> 
    </DataGrid.Columns> 
</DataGrid> 

代碼隱藏:

public class UnitConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     string result = null; 

     ObservableCollection<DataGridColumn> columns = values[0] as ObservableCollection<DataGridColumn>; 
     string headerName = values[1].ToString(); 

     var coll = columns.Where(x => x.Header.ToString() == headerName).FirstOrDefault(); 

     if (coll != null) 
      result = CustomHeader.GetUnit(coll); 

     return result; 
    } 

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

我認爲更好的解決方案將是創建新類如HeaderData之後,你可以在XAML中創建它的實例,並結合這個班。

例子:

類持有頭數據:

class HeaderData 
{ 
    public string Name { get; set; } 
    public string Unit { get; set; } 
} 

XAML代碼:

<DataGrid x:Name="tObjectDataGrid" Margin="10,50,10,10" 
      AutoGenerateColumns="False" EnableRowVirtualization="True" 
      ItemsSource="{Binding ObjectList}" 
      RowDetailsVisibilityMode="VisibleWhenSelected" > 
    <DataGrid.Resources> 
     <DataTemplate x:Key="CustomHeaderTemplate"> 
      <StackPanel> 
       <TextBlock Text="{Binding Name}" /> 
       <TextBlock Text="{Binding Unit}" /> 
      </StackPanel> 
     </DataTemplate> 
    </DataGrid.Resources> 
    <DataGrid.Columns> 
     <DataGridTextColumn x:Name="SpeedColumn" 
         Width="1*" 
         Binding="{Binding Speed}"         
         HeaderTemplate="{StaticResource CustomHeaderTemplate}">    
      <DataGridTextColumn.Header> 
       <cust:HeaderData Name="Speed" Unit="[m/s]" /> 
      </DataGridTextColumn.Header> 
     </DataGridTextColumn> 
     <DataGridTextColumn x:Name="SpeedColumn2" 
         Width="1*" 
         Binding="{Binding Speed2}"         
         HeaderTemplate="{StaticResource CustomHeaderTemplate}"> 
      <DataGridTextColumn.Header> 
       <cust:HeaderData Name="Speed2" Unit="[km/h]" /> 
      </DataGridTextColumn.Header> 
     </DataGridTextColumn> 
    </DataGrid.Columns> 
</DataGrid> 
+0

謝謝。第二種方法從輕鬆的角度看起來非常好。所以我將其標記爲答案。 我只是想知道,因爲我認爲附加屬性應該正好解決我遇到的這樣一個點。 當我想在cust中綁定兩個textvalues:HeaderData我想我必須實現作爲dependencyproperties的屬性?或者我必須從dependencyobject派生? – LaWi

+0

不,您可以創建簡單的屬性,而不必從DependencyObject派生。在我的回答中,我向你展示了示例課程。 – kmatyaszek

+0

我正在嘗試使用這個解決方案,但與'TextBox'的雙向綁定。因此,我不想使用硬編碼的值'Unit =「[km/h]」',我想要'Unit =「{Binding Unit,Mode = TwoWay}」''。 我嘗試使用附加屬性和單獨的類,但是我無法將值傳播回我的視圖模型。在附屬性示例中,問題出現在'ConvertBack'中,因爲我沒有如何調用SetUnit(obj,value)'的信息。在'HeaderData'的情況下,我得到了'HeaderData.Unit'屬性的值,但並沒有回到我的視圖模型。我現在完全卡住了。 – lukeguy

1

乍一看,你的代碼是正常的,應該工作。但是當您的依賴屬性設置爲DataGridTextColumn,SetUnit未調用且變量UnitNULL。我試圖在Window分配附加依賴屬性的值(因爲它連接,你可以在任何地方設置它的值)在這種情況下,必須努力:

<Window x:Class="DataGridAttachedHelp.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:DataGridAttachedHelp" 
    local:CustomHeader.Unit="[m/s]" 
    Name="MyWindow" 
    Title="MainWindow" Height="350" Width="525" 
    WindowStartupLocation="CenterScreen"> 

<Grid> 
    <DataGrid x:Name="tObjectDataGrid" Margin="10,50,10,10" 
       AutoGenerateColumns="False" EnableRowVirtualization="True"      
       RowDetailsVisibilityMode="VisibleWhenSelected" > 

     <DataGrid.Resources> 
      <DataTemplate x:Key="CustomHeaderTemplate"> 
       <StackPanel> 
        <TextBlock Text="{Binding}" /> 
        <TextBlock Text="{Binding Path=(local:CustomHeader.Unit), ElementName=MyWindow}" /> 
       </StackPanel> 
      </DataTemplate> 
     </DataGrid.Resources> 

     <DataGrid.Columns> 
      <DataGridTextColumn x:Name="SpeedColumn" Width="1*" Binding="{Binding Speed}" Header="Speed" 
        HeaderTemplate="{StaticResource CustomHeaderTemplate}" /> 
     </DataGrid.Columns> 
    </DataGrid>  
</Grid> 
</Window> 

在你的情況下,物業沒有工作,因爲它是必要的以指示屬性的來源,例如:ElementName,Source。因此,只需在參數ElementNameDataGridTextColumn名稱:

<TextBlock Text="{Binding Path=(local:CustomHeader.Unit), ElementName=SpeedColumn}" /> 
+1

謝謝你的回覆。這解決了一個DataColumn。我也嘗試使用RelativeSource進行綁定,但未能在我的示例中獲得正確的祖先。我的目的是,爲每個列使用DynamicResource字符串,圖像等輕鬆地在頁眉上應用更多信息。因此,直接在window/usercontrol-level上通過附加屬性進行管理並不完全符合我的需求。 – LaWi