3

データがコレクションであるデータグリッドにデータを表示したい

public class Thing
{
    public string Foo { get; set; }
    public string Bar { get; set; }
    public List<Candidate> Candidates { get; set; }
}

public class Candidate
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    ...
}

ここで、候補リスト内の候補の数は実行時に変化します。

望ましいグリッド レイアウトは次のようになります

Foo | Bar | Candidate 1 | Candidate 2 | ... | Candidate N

DataTemplate実行時に変更する予定なので、各候補を作成したいと思います-ユーザーは、候補に関するどの情報を異なる列に表示するかを選択できます(候補は単なる例であり、私は異なるオブジェクトを持っています)。つまり、実行時に列テンプレートも変更したいということですが、これは 1 つの大きなテンプレートとその部分を折りたたむことで実現できます。

私は自分の目標を達成する方法を 2 つ知っています (どちらも非常に似ています)。

  1. AutoGeneratingColumnイベントを使用して候補者列を作成する
  2. 列を手動で追加する

DataTemplateどちらの場合も、 from 文字列を でロードする必要がありますXamlReader。その前に、文字列を編集してバインディングを必要なCandidateに変更する必要があります。

DataGridTemplateColumn の数が不明な DataGrid を作成するより良い方法はありますか?

注:この質問は、valueconverter を使用した動的データ テンプレートに基づいています。

編集: WPF と Silverlight の両方をサポートする必要があるため、列のコレクションをバインドする独自のDataGridコンポーネントを作成しました。DependencyPropertyコレクションが変更されたら、列を更新します。

4

3 に答える 3

2

たとえば、2 つの DataTemplate と ContentControl を作成します。

<DataTemplate DataType="{x:Type viewModel:VariantA}"> <dataGrid...> </DataTemplate>
<DataTemplate DataType="{x:Type viewModel:VariantB}"> <dataGrid...> </DataTemplate>

<ContentControl Content="{Binding Path=GridModel}" />

GridModel プロパティ (タイプ オブジェクトなど) を VariantA または VariantB に設定すると、DataTemplate が切り替わります。

VariantA & B の実装例:

public class VariantA
{
    public ObservableCollection<ViewModel1> DataList { get; set; }
}

public class VariantB
{
    public ObservableCollection<ViewModel2> DataList { get; set; }
}

お役に立てれば。

于 2011-01-11T07:17:51.557 に答える
0

私は同様の問題を調べてきましたが、有用なパターンはほんの一握りしか見つかりませんでした。「動的列」の問題全体は、Silverlightでは興味深い問題です。

昨日、検索中にTravisPettijohnのサイトでこのページSilverlightDataGrid withDynamicColumnsを見つけました。

以前は、 Colin Eberhardtによって概説された「インデックスコンバーター」パターンを使用していました。これは、使用している限り、非常にうまく機能しますDataGridTextColumn。すべてはコードビハインドで実行でき、実行時にスタイルを適用するのに問題はありませんでした。ただし、私の要件は、「セルレベル」の書式設定を適用することです(セルの背景を変更するなど)。これは、DataGridTemplateColumnが必要であることを意味します。

DataGridTemplateColumn私にとっての大きな問題は、コードでバインディングを設定できないことでした。xamlを解析することでビルドできることはわかっていますが、他のすべての人と同じように、大規模なハックのように見え、n番目までは保守できません。

Travis(上記の最初のリンク)によって概説されたパターンは完全に異なります。「実行時」(つまり、ページの読み込み時)に、グリッドに必要な列を作成します。これは、コレクションを反復処理し、適切なヘッダーなどを使用して各アイテムの列を追加することを意味します。次に、RowLoadedイベントのハンドラーを実装し、各行が読み込まれるときに、各セルのDataContextを適切なプロパティ/プロパティインデックスに設定します。親。

private void MyGrid_RowLoaded(object sender, EventArgs e)
{
    var grid = sender as DataGrid;
    var myItem = grid.SelectedItem as MyClass;
    foreach (int i = 0; i < myItem.ColumnObjects.Count; i++)
    { 
        var column = grid.Columns[i]; 
        var cell = column.GetCellContent(e.Row)
        cell.DataContext = myItem.ColumnObjects[i];
    }
}

これにより、インデックスコンバーターを使用する必要がなくなりました。Binding設定するときにおそらくを使用できますcell.DataContextが、私にとっては、テンプレートを基になるオブジェクトに直接バインドする方が簡単です。

現在、複数のテンプレート(それぞれがセルオブジェクトの同じプロパティにバインドできる)を用意し、ページの読み込み時にそれらを切り替えることを計画しています。非常にきちんとしたソリューション。

于 2011-11-21T20:43:53.480 に答える
0

これはかなりいままなので、これが「より良い」方法であるかどうかはわかりませんが、個人的には次のようにしました。

  • テンプレートをxamlで作る
  • 現在のバインディング + 列へのバインディングを取得するマルチバインドを使用して、「正しい」dataContext (つまり、行ではなくセル) を取得します。
  • このバインディングでコンバーターを使用して、必要なプロパティの値を取得します。取得するプロパティが多数ある場合は、必要に応じてパラメーターを追加します。

例:(申し訳ありませんが、あなたのプロジェクトに合わせてコードを調整しませんでしたが、そこから自分でできるはずです)

ここに私のデータテンプレートがあります:

<DataTemplate x:Key="TreeCellTemplate">
    <Grid>
        <TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5,0,0,0">
            <TextBlock.Text>
                <MultiBinding Converter="{StaticResource RowColumnToCellConverter}" ConverterParameter="Text">
                    <Binding />
                    <Binding RelativeSource="{RelativeSource AncestorType=DataGridCell}" Path="Column" />
                </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
    </Grid>
</DataTemplate>

ここに私のコンバーターがあります:

   public class RowColumnToCellConverter : MarkupExtension, IMultiValueConverter
   {
      public RowColumnToCellConverter() { }

      public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
      {
         XwpfRow row = values[0] as XwpfRow;
         XwpfTreeColumn column = values[1] as XwpfTreeColumn;

         if (row == null || column == null) return DependencyProperty.UnsetValue;

         TreeCell treeCell = (TreeCell)row[column.DataGrid.Columns.IndexOf(column)];
         switch ((string)parameter)
         {
            case "Text": return treeCell.Text;
            case "Expanded": return treeCell.Expanded;
            case "ShowExpandSymbol": return treeCell.ShowExpandSymbol;
            case "CurrentLevel": return new GridLength(treeCell.CurrentLevel * 14);

            default:
               throw new MissingMemberException("the property " + parameter.ToString() + " is not defined for the TreeCell object");
         }
      }

      public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
      {
         throw new NotSupportedException();
      }

      public override object ProvideValue(IServiceProvider serviceProvider)
      {
         return new RowColumnToCellConverter();
      }
   }

これによりMVVMモデルが保存されます.xamlパーサーを使用して「動的」データテンプレートを作成するのは本当に嫌いなので、この方法を好みますが、それでも私の観点からは醜いハックです.

MS の連中が、テンプレート化された列をその場で生成できるように、dataContexts として行ではなくセルを取得する方法を提供してくれることを願っています...

お役に立てれば

編集:あなたの場合、コンバーターは実際にはもっと単純でなければなりません(私が間違っていなければ、セルのインスタンスを直接返すことができ、パラメーターは必要ありません)が、それでもより複雑なバージョンを残しました。他の誰かが同様の問題を抱えている場合に備えて

于 2011-02-07T15:46:58.177 に答える