Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/256.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用于统一网格绑定的DataTemplateSelector?_C#_Wpf_Xaml - Fatal编程技术网

C# 用于统一网格绑定的DataTemplateSelector?

C# 用于统一网格绑定的DataTemplateSelector?,c#,wpf,xaml,C#,Wpf,Xaml,从Ed昨天在我的问题()中所说的开始,我试图创建一个统一的网格,第一行和第一列填充为文本块,其余单元格填充为按钮。下面是一个例子 现在,我不完全确定如何绑定这一切。我几乎可以使用CompositeContainer实现它,但是我想使用来自ObjSource和ObjLabeller的数据绑定网格的行和列。。。但我不知道该怎么做 以下是我的虚拟机中的代码: private CompositeCollection objGridLabelCompositeCollection; pu

从Ed昨天在我的问题()中所说的开始,我试图创建一个统一的网格,第一行和第一列填充为文本块,其余单元格填充为按钮。下面是一个例子

现在,我不完全确定如何绑定这一切。我几乎可以使用CompositeContainer实现它,但是我想使用来自ObjSource和ObjLabeller的数据绑定网格的行和列。。。但我不知道该怎么做

以下是我的虚拟机中的代码:

    private CompositeCollection objGridLabelCompositeCollection;
    public CompositeCollection ObjGridLabelCompositeCollection
    {
        get { return objGridLabelCompositeCollection; }
        set { objGridLabelCompositeCollection= value;
            OnPropertyChanged("ObjGridLabelCompositeCollection");
        }
    }

    private ObservableCollection<GridLabeller> GridLabeller = new ObservableCollection<gridLabeller >();
    public ObservableCollection<GridLabeller> GridLabeller 
    {
        get { return gridLabeller; }
        set
        {
            gridLabeller = value;
            OnPropertyChanged(nameof(GridLabeller));
        }
    }

    private ObservableCollection<ObjA> objSource = new ObservableCollection<ObjA>();
    public ObservableCollection<ObjA> ObjSource
    {
        get { return objSource; }
        set
        {
            objSource = value;
            OnPropertyChanged(nameof(ObjSource));
        }
    }

    private void Generate(object rowAndColumn)
    {
        // Cast our object to a tuple
        Tuple<int, int> rowColumnForGrid = rowAndColumn as Tuple<int, int>;

        // Set Row - add 1 for header
        RowCount = rowColumnForGrid.Item1 + 1;

        // Set Column - add 1 for header
        ColumnCount = rowColumnForGrid.Item2 + 1;

        ObjSource.Clear();

        for (int iRow = 0; iRow < RowCount; ++iRow)
        {
            for (int iCol = 0; iCol < ColumnCount; ++iCol)
            {
                if (iRow == 0 && iCol == 0)
                {
                    continue;
                }

                if (iRow == 0 || iCol == 0)
                {
                    // Create label
                    GridLabeller label = new GridLabeller();

                    if (iRow == 0)
                    {
                        label.HeaderName = iCol.ToString();
                    }

                    if (iCol == 0)
                    {
                        label.HeaderName = GridHelpers.GetRowName(iRow);
                    }

                    label.Row = iRow;
                    label.Column = iCol;

                    GridLabeller.Add(label);
                }
                else
                {
                    // Create ObjA 
                    ObjA objee = new ObjA();
                    objee.Id = GridHelpers.GetRowName(iRow) + (iCol);
                    objee.Row = iRow;
                    objee.Column = iCol;
                    ObjSource.Add(objee);
                }
            }
        }

        ObjGridLabelCompositeCollection = new CompositeCollection();
        ObjGridLabelCompositeCollection.Add(new CollectionContainer() { Collection = GridLabeller });
        ObjGridLabelCompositeCollection.Add(new CollectionContainer() { Collection = ObjSource });
    }
以及网格中的XAML

                                <ItemsControl ItemsSource="{Binding ObjGridLabelCompositeCollection}">
                                    <ItemsControl.ItemsPanel>
                                        <ItemsPanelTemplate>
                                            <UniformGrid DockPanel.Dock="Top" HorizontalAlignment="Stretch" 
                                             VerticalAlignment="Stretch" Grid.Row="1" 
                                             Rows="{Binding RowCount}"
                                             Columns="{Binding ColumnCount}"/>
                                        </ItemsPanelTemplate>
                                    </ItemsControl.ItemsPanel>
                                    <ItemsControl.ItemContainerStyle>
                                        <Style>
                                            <Setter Property="Grid.Row" Value="{Binding Row}"/>
                                            <Setter Property="Grid.Column" Value="{Binding Column}"/>
                                        </Style>
                                    </ItemsControl.ItemContainerStyle>
                                    <ItemsControl.Resources>
                                        <DataTemplate DataType="{x:Type engine:ObjA}">
                                            <Button Content="{Binding Id}" />
                                        </DataTemplate>
                                        <DataTemplate DataType="{x:Type engine:GridLabeller}">
                                            <TextBlock Text="{Binding HeaderName}"/>
                                        </DataTemplate>
                                    </ItemsControl.Resources>
                                </ItemsControl>

现在看来是这样的。。。第一张图片是我想要的

抱歉,没有足够的代表发布图像


不管怎样,如果有人有什么好主意,我将不胜感激!也许我需要一些复合收藏。。。我不知道…

这个例子展示了如何实现一个动态的
数据网格
,其中每个单元格都是一个
按钮
元素。您需要稍微修改它(数据类型)以满足您的需求

我建议使用已经有列和行标题的
DataGrid
。使用
DataTable
填充
DataGrid
DataTable
简化了动态列生成,并使数据模型没有冗余数据(例如列标题等)

要覆盖单元格布局,需要设置
DataGrid.CellStyle
,在本例中,这将使单元格变成
按钮。此修改还需要将类型为
DataRowView
的列数据转换为实际显示数据(在本例中为
CellDataModel
),然后将其绑定到
按钮。Content

要显示行号,需要第二个转换器来生成
DataGridRowHeader
的值。
DataGridRowHeader
是通过设置
DataGrid.RowHeaderStyle
来定义的

CellDataModel.cs

public class CellDataModel
{
  public CellDataModel(object data)
  {
    this.Data = data;
  }

  public object Data { get; set; }
}
class DataRowViewToCellDataConverter : IMultiValueConverter
{
  #region Implementation of IMultiValueConverter

  /// <inheritdoc />
  public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
  {
    if (values[0] is DataRowView dataRowView 
        && ((int) values[1]) is int cellIndex
        && dataRowView[cellIndex] is CellDataModel cellModel)
    {
      return cellModel.Data;
    }

    return Binding.DoNothing;
  }

  /// <inheritdoc />
  public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
    throw new NotSupportedException();

  #endregion
}
class RowDataToRowNumberConverter : IMultiValueConverter
{
  #region Implementation of IMultiValueConverter

  /// <inheritdoc />
  public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
  {
    if (values[0] is DataGrid dataGrid && values[1] is object rowData)
    {
      return dataGrid.Items.IndexOf(rowData) + 1;
    }

    return Binding.DoNothing;
  }

  /// <inheritdoc />
  public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
    throw new NotSupportedException();

  #endregion
}
ViewModel.cs

class ViewModel
{
  public DataTable GridSource { get; set; }

  public ViewModel()
  {
    // Create a data set with an arbitrary column and row count
    this.GridSource = new DataTable();

    // Create column headers with alphabetic letters from 'A' to 'G'. 
    // The decimal ASCII value is converted to a string.
    for (var asciiCode = 65; asciiCode < 72; asciiCode++)
    {
      this.GridSource.Columns.Add(new DataColumn(new string((char) asciiCode, 1), typeof(CellDataModel)));
    }

    // Populate data table
    int maxNumberOfRows = 5;
    for (var rowNumber = 1; rowNumber <= maxNumberOfRows; rowNumber++)
    {
      DataRow newRow = this.CellTable.NewRow();
      foreach (DataColumn tableColumn in this.CellTable.Columns)
      {
        newRow[tableColumn.ColumnName] = new CellDataModel($"Value: {rowNumber}{tableColumn.ColumnName}");
      }

      this.GridSource.Rows.Add(newRow);
    }
  }
}
类视图模型
{
公共数据表GridSource{get;set;}
公共视图模型()
{
//创建具有任意列数和行数的数据集
this.GridSource=新数据表();
//使用字母“A”到“G”创建列标题。
//十进制ASCII值将转换为字符串。
对于(变量ASCICODE=65;ASCICODE<72;ASCICODE++)
{
Add(新数据列(新字符串((char)ascicode,1),typeof(CellDataModel));
}
//填充数据表
int maxNumberOfRows=5;
对于(var rowNumber=1;rowNumber)
抛出新的NotSupportedException();
#端区
}
RowDataToRowNumberConverter.cs

public class CellDataModel
{
  public CellDataModel(object data)
  {
    this.Data = data;
  }

  public object Data { get; set; }
}
class DataRowViewToCellDataConverter : IMultiValueConverter
{
  #region Implementation of IMultiValueConverter

  /// <inheritdoc />
  public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
  {
    if (values[0] is DataRowView dataRowView 
        && ((int) values[1]) is int cellIndex
        && dataRowView[cellIndex] is CellDataModel cellModel)
    {
      return cellModel.Data;
    }

    return Binding.DoNothing;
  }

  /// <inheritdoc />
  public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
    throw new NotSupportedException();

  #endregion
}
class RowDataToRowNumberConverter : IMultiValueConverter
{
  #region Implementation of IMultiValueConverter

  /// <inheritdoc />
  public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
  {
    if (values[0] is DataGrid dataGrid && values[1] is object rowData)
    {
      return dataGrid.Items.IndexOf(rowData) + 1;
    }

    return Binding.DoNothing;
  }

  /// <inheritdoc />
  public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
    throw new NotSupportedException();

  #endregion
}
class RowDataToRownNumber转换器:IMultiValueConverter
{
#IMultiValueConverter的区域实现
/// 
公共对象转换(对象[]值,类型targetType,对象参数,CultureInfo区域性)
{
如果(值[0]是DataGrid DataGrid&&values[1]是对象行数据)
{
返回dataGrid.Items.IndexOf(rowData)+1;
}
不做任何事;
}
/// 
公共对象[]转换回(对象值、类型[]目标类型、对象参数、文化信息文化)=>
抛出新的NotSupportedException();
#端区
}
main window.xaml

<Window>
  <Window.DataContext>
    <ViewModel />
  </Window.DataContext>

  <DataGrid ItemsSource="{Binding GridSource}" 
            AutoGeneratingColumn="DataGrid_OnAutoGeneratingColumn" 
            IsReadOnly="True">

    <DataGrid.Resources>
      <DataRowViewToCellDataConverter x:Key="DataRowViewToCellDataConverter" />
      <RowDataToRowNumberConverter x:Key="RowDataToRowNumberConverter" />
    </DataGrid.Resources>

    <DataGrid.CellStyle>
      <Style TargetType="DataGridCell">
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate TargetType="DataGridCell">

              <Button>
                <Button.Content>
                  <MultiBinding Converter="{StaticResource DataRowViewToCellDataConverter }">
                    <Binding RelativeSource="{RelativeSource TemplatedParent}" 
                             Path="DataContext" />
                    <Binding RelativeSource="{RelativeSource TemplatedParent}"
                             Path="TabIndex" />
                  </MultiBinding>
                </Button.Content>
              </Button>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>
    </DataGrid.CellStyle>

    <DataGrid.RowHeaderStyle>
      <Style TargetType="{x:Type DataGridRowHeader}">
        <Setter Property="Content">
          <Setter.Value>
            <MultiBinding Converter="{StaticResource RowDataToRowNumberConverter}">
              <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=DataGrid}" />
              <Binding />
            </MultiBinding>
          </Setter.Value>
        </Setter>
      </Style>
    </DataGrid.RowHeaderStyle>
  </DataGrid>
</Window>

此示例生成以下输出:


您可以添加更多细节吗?您的目标是什么?按钮应该做什么?它们是否像第一张图中一样是空的?嗨,BionicCode。我们不需要太担心按钮的功能(它们可以选择、拖动等)。但我有代码来做这件事(将所有代码都移植到MVVM中的UserControl更好)。我已经让它工作了一半,但是我不能让ItemContainerStyle为网格行和列工作。ObjSource和ObjLabeller都有一个行和列变量。让我更新我的答案,以便您可以看到它是什么样子。列计数是常量吗?不,它是动态的。让我发布代码。行计数和列计数都由dy绑定纳米奇value@BionicCode请参阅更新-谢谢。所有内容都显示得很好,但显然没有考虑ObjSource和GridLabeller的行和列,因为它们都有一个行/列变量,所以不知道绑定到哪个行/列变量