Как я могу связать Wpf DataGridColumn с объектом? - PullRequest
5 голосов
/ 19 мая 2009

Я хочу привязать столбцы моей WPF DataGrid к некоторым объектам в Словаре, например:

Binding Path = Objects [i]

где Objects - мой словарь объектов, так что каждая ячейка будет представлять элемент Object. Как я могу это сделать?

Полагаю, мне нужно создать шаблон для своей ячейки, что я и сделал, но как получить результат привязки столбцов в моем шаблоне? Я знаю, что по умолчанию содержимое DataGridCell представляет собой TextBlock, а его свойство Text задается в результате привязки столбца, но если этот результат является объектом, я предполагаю, что мне нужно создать ContentTemplate. Как мне это сделать, поскольку то, что я пробовал, ничего не отображает.

Вот что я попробовал:

<Style x:Key="CellStyle" TargetType="{x:Type dg:DataGridCell}">
    <Setter Property="Template"> ---it should realy be ContentTemplate?
      <Setter.Value>
        <ControlTemplate>
          <controls:DataGridCellControl CurrentObject="{Binding }"/> -- I would expect to get the object like this for this column path : Path=Objects[i] but is not working
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>

Итак, для полной ясности, я хочу получить в свойстве CurrentObject моего DataGridCellControl текущий объект, который должен получиться, если я установлю привязку столбца в моей сетке данных, как этот Path = Objects [i].

Спасибо за любые предложения,

Джон.

Ответы [ 2 ]

0 голосов
/ 02 сентября 2009

Я создал несколько вспомогательных классов, чтобы использовать DataGrid как своего рода DataTable. Другими словами, я хотел форматировать, сортировать и полировать внешний вид DataGrid без необходимости предварительно создавать некоторые классы заранее. Основная причина, по которой я хотел это, была для набора тестов, я хотел иметь возможность создавать произвольное количество столбцов и во время выполнения. Вот что я получил

public class DataRow
{
    internal List<object> Items = new List<object>();

    public object this[string value]
    {
        get { return Items[Convert.ToInt32(value)]; }
    }

    public string GetString(int index)
    {
        return Items[index].ToString();
    }

    public object GetObject(int index)
    {
        return Items[index];
    }

    public DataRow(params object[] values)
    {
        if (values == null || values.Length < 1)
            throw new Exception("You must pass in some values");

        Items.AddRange(values);            
    }
}  

public class GridConstructor
{
    public List<DataRow> Rows = new List<DataRow>();
    private DataRow headers;

    public GridConstructor(DataRow head)
    {
        headers = head;
    }

    public void BuildInto(DataGrid grid)
    {
        grid.AutoGenerateColumns = false;
        grid.Columns.Clear();
        int totalCols = 0;

        Type headType = headers.GetType();

        for (int i = 0; i < headers.Items.Count; i++)
        {
            grid.Columns.Add(GetCol(headers.GetString(i), String.Concat("[", i.ToString(),"]")));
            totalCols++;
        }                     

        int finalWidth = totalCols * (int)grid.ColumnWidth.Value + 15;
        grid.Width = finalWidth;

        grid.ItemsSource = Rows;
    }

    private DataGridTextColumn GetCol(string header, string binding)
    {
        DataGridTextColumn col = new DataGridTextColumn();
        col.IsReadOnly = true;            
        col.Header = header;
        col.Binding = new Binding(binding);

        return col;
    }

    public DataGrid Create(int colSize)
    {
        DataGrid grid = new DataGrid();
        grid.ColumnWidth = colSize;
        grid.CanUserAddRows = false;
        grid.AlternationCount = 2;
        BuildInto(grid);
        return grid;
    }
}

Соединяя это, это пример использования:

void SimpleTest_Loaded(object sender, RoutedEventArgs e)
    {            
        DataRow headers = new DataRow("Level", "Weapon Type", "vs None", "vs Leather", "vs Studded", "vs Brigandine");            
        GridConstructor gridConstructor = new GridConstructor(headers);            

        var weaponType = "Slash";
        for (int level = 1; level < 10; level++)
        {
            int damage = DiceCup.RollMulti(8, level);
            int damCloth = damage - DiceCup.RollMulti(2, level);
            int damLeather = damage - DiceCup.RollMulti(3, level);
            int damStudded = damage - DiceCup.RollMulti(4, level);
            int damBrigandine = damage - DiceCup.RollMulti(5, level);

            DataRow row = new DataRow(level, weaponType, damage, damCloth, damLeather, damStudded, damBrigandine);
            gridConstructor.Rows.Add(row);                
        }

        //Create the grid.
        var grid = gridConstructor.Create(100);


        //Create a chart.
        Chart chart = new Chart();
        chart.Height = 200;
        chart.LegendTitle = "Legend";
        chart.Title = "Slash vs Armor Types";                       
        chart.DataContext = gridConstructor.Rows;            


        //Create our series, or lines.
        LineSeries slashVsNone = new LineSeries();
        slashVsNone.Title = "vs None";
        slashVsNone.DependentValueBinding = new Binding("[2]");
        slashVsNone.IndependentValueBinding = new Binding("[0]");
        slashVsNone.ItemsSource = gridConstructor.Rows;            
        chart.Series.Add(slashVsNone);

        //Presentation is a stackpanel on the page.            
        presentation.Children.Add(grid);
        presentation.Children.Add(chart);             
    }

И вывод:

альтернативный текст http://quiteabnormal.com/images/codeSample.jpg

Обратите внимание, что раскраска сетки происходит от универсальных стилей, установленных на странице. Если вы используете метод GridConstructor.BuildInto (), вы можете указать сетку, которую вы предварительно отформатировали, в Blend или что-то подобное.

Только одна вещь, GridConstructor делает некоторые предположения о начальных настройках столбца. Вы можете изменить класс, чтобы сделать его более настраиваемым, если хотите, но это то, что мне было нужно, поэтому я хотел иметь возможность сделать это без суеты.

0 голосов
/ 19 мая 2009

Попробуйте это:

<ListView x:Name="listViewUsers" SelectionMode="Single" 
                              ItemsSource="{Binding ElementName=window1, Path=Users, Mode=TwoWay}" MouseDoubleClick="listViewUsers_MouseDoubleClick">
                        <ListView.View>
                            <GridView x:Name="gridViewUsers" AllowsColumnReorder="False">
                                <GridViewColumn>
                                    <GridViewColumn.CellTemplate>
                                        <DataTemplate>
                                            <Image Source="{Binding Path=IsAdministrator, Converter={StaticResource boolToImage}, ConverterParameter='Images/admin18.gif|Images/user18.gif'}" />
                                        </DataTemplate>
                                    </GridViewColumn.CellTemplate>
                                </GridViewColumn>
                                <GridViewColumn Header="User Name" DisplayMemberBinding="{Binding Path=UserName}" Width="140" />
                                <GridViewColumn Header="Full Name" DisplayMemberBinding="{Binding Path=FullName}" Width="140" />
                                <GridViewColumn Header="Phone Number" DisplayMemberBinding="{Binding Path=PhoneNumber}" Width="110" />
                                <GridViewColumn Header="Access Type" DisplayMemberBinding="{Binding Path=AccessType}" Width="110">
                                </GridViewColumn>
                                <GridViewColumn>
                                    <GridViewColumn.CellTemplate>
                                        <DataTemplate>
                                            <Image Cursor="Hand" ToolTip="Delete User" Stretch="None" Source="Images/trash12.gif" MouseUp="DeleteUser" />
                                        </DataTemplate>
                                    </GridViewColumn.CellTemplate>
                                </GridViewColumn>
                            </GridView>
                        </ListView.View>
                    </ListView>

Где в ItemsSource = "{Binding ElementName = window1, Path = Users, Mode = TwoWay}"

  • ElementName - это имя окна в XAML (просто добавьте x: Name = "window1" в тег Window, как и в любом другом контроле.

  • Пользователи - это список, должен работать так же, как словарь

  • Mode = TwoWay означает, что если сетка будет изменена, список также будет изменен, и наоборот (Двухстороннее связывание)

EDIT:

Попробуйте это:

XAML:

<ListView x:Name="listViewTest" ItemsSource="{Binding}">
<ListView.View>
    <GridView x:Name="gridViewTest">

    </GridView>
</ListView.View>
</ListView>

C #:

public class TheClass
    {
        public int Col1, Col2, Col3; 
        public Dictionary<int, OtherColumns> otherColumns = new Dictionary<int,OtherColumns>();
    }

    public class OtherColumns
    {
        public string ColumnName;
        public int Value;
    }

И вызовите этот метод в Window_Loaded:

private void PopulateListView()
        {
            TheClass c = new TheClass();

            c.Col1 = 10;
            c.Col2 = 20;
            c.Col3 = 30;


            c.otherColumns.Add(0, new OtherColumns() { ColumnName = "Col4", Value = 40 });
            c.otherColumns.Add(1, new OtherColumns() { ColumnName = "Col5", Value = 50 });
            c.otherColumns.Add(3, new OtherColumns() { ColumnName = "Col6", Value = 60 });

            DataTable table = new DataTable();

// adding regular columns
            table.Columns.Add("Col1", typeof(int));
            table.Columns.Add("Col2", typeof(int));
            table.Columns.Add("Col3", typeof(int));

// adding dynamic columns
            foreach (KeyValuePair<int, OtherColumns> pair in c.otherColumns)
            {
                table.Columns.Add(pair.Value.ColumnName, typeof(int));
            }

            DataRow row = table.NewRow();

// adding regular column values to the DataTable
            row["Col1"] = c.Col1;
            row["Col2"] = c.Col2;
            row["Col3"] = c.Col3;

// adding dynamic column values to the DataTable
            foreach (KeyValuePair<int, OtherColumns> pair in c.otherColumns)
            {
                row[pair.Value.ColumnName] = pair.Value.Value;
            }

            table.Rows.Add(row);

            // Start binding the table.
            gridViewTest.Columns.Clear();

            System.Windows.Controls.GridViewColumn gvc;
            Binding binding;

            foreach (DataColumn column in table.Columns)
            {
                gvc = new System.Windows.Controls.GridViewColumn();
                binding = new System.Windows.Data.Binding();
                binding.Path = new PropertyPath(column.ColumnName);
                binding.Mode = BindingMode.OneWay;
                gvc.Header = column.Caption;
                gvc.DisplayMemberBinding = binding;
                gridViewTest.Columns.Add(gvc);
            }

            listViewTest.DataContext = table;
        }

Я не говорю, что это лучшее решение, но оно может помочь. Дайте мне знать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...