Как выровнять числовые столбцы DataGrid вправо в коде?

РЕДАКТИРОВАТЬ Решено:

Благодаря проницательности ответов и комментариев я смог найти решение, которое соответствует моим потребностям. Из-за того, что сетка данных создается динамически и повторно используется в цикле, чтобы ее можно было вставить в древовидную структуру, большинство вещей, которые мне нужно было сделать, нельзя было сделать в XML (насколько мне известно, я потратил полдня на попытки чтобы найти способ заставить это работать, но этого просто не происходило.) Из-за того, что HighCore принижает мой код (что было необходимо и основано на фактах, но заставило меня зализывать раны, поскольку я гордился этим) я перешел к подход с привязкой данных. Если у вас не хватило терпения прочитать оставшуюся часть этого абзаца, пример кода приведен ниже. Это сделало мой код намного чище и позволило мне добавлять Binded DataGridTextColumns в DataGrid, которые можно было отформатировать с помощью встроенного установщика кода. Я смог создать сеттер в коде, сославшись на ответ Шеридана, который дал мне все, что мне было нужно. Код ниже.

while (bc.next != null)
{
    bc = bc.next;
    System.Windows.Controls.DataGrid dgbc = new System.Windows.Controls.DataGrid()
    dgbc.AutoGenerateColumns = false;

    Style style = new Style(typeof(System.Windows.Controls.DataGridCell));
    Setter setter = new     Setter(System.Windows.Controls.DataGridCell.HorizontalAlignmentProperty, System.Windows.HorizontalAlignment.Right);
    style.Setters.Add(setter);

    DataGridTextColumn dgtc = new DataGridTextColumn();
    dgtc.Binding = new System.Windows.Data.Binding("pBudgetCode");
    dgtc.Header = "Budget Code";
    dgbc.Columns.Add(dgtc);

    DataGridTextColumn dgtc2 = new DataGridTextColumn();
    dgtc2.Binding = new System.Windows.Data.Binding("pOriginalEstimate");
    dgtc2.CellStyle = style;
    dgtc2.Header = "Original Estimate";
    dgbc.Columns.Add(dgtc2);

    //More Columns added, dgtc above intentionally did not use the style.

    LinkedList<BudgetCodeCTC> tempCode = new LinkedList<BudgetCodeCTC>();
    tempCode.AddLast(bc.getCTCProps());
    dgbc.ItemsSource = tempCode;

    //BudgetCodeCTC is the class that contains the properties to be bound.
    //The paramater in creation of the Binding object is the name of the Property in BudgetCodeCTC that the column is bound to.

    foreach(BudgetCategoryCTC catCTC in tempCode.ElementAt(0).pAccumulateAs)
    {
         //Essentially same code as above except applied at the next level down in the TreeView and then added to the Parent TreeViewItem

          //Another foreach loop for the next level down using essentially the same code
    }

Я знаю, что это всего лишь снимок кода, но, надеюсь, он предоставит достаточно информации для тех, кто ищет похожее решение.

Пример того, как это выглядит:

введите здесь описание изображения

  • Я пропустил некоторые вещи и объяснил упрощенную версию того, что пропущено в комментариях, обозначенных //
  • В то время как циклические тесты выполняются на объектах, которые используют .next для добавления возможности связанного списка к объекту без всех накладных расходов (я знаю, что нахожусь в меньшинстве, делая это вместо использования LinkedList ‹>, я сомневаюсь, что убедит ты используешь мой путь, и я знаю, что ты меня не убедишь).
  • Также упоминаются winforms, поскольку они используются в пропущенных областях из-за предпочтений конечных пользователей (сражались в добром бою и проиграли). Я удалил некоторые из System.Windows.Controls. Чтобы вам не пришлось прокручивать кодовое поле слишком далеко, уверяю вас, код компилируется и запускается.

            while (bc.next != null)
            {
                bc = bc.next;
                budgetCodeCategory mat = bc.materials;
                budgetCodeCategory equ = bc.equipment;
                budgetCodeCategory sub = bc.sub;
                budgetCodeCategory oth = bc.other;
                budgetCodeCategory lab = bc.labor;
                budgetCodeCategory ovh = bc.overhead;
                DataTable t = new DataTable();
                t.Columns.Add("Budget Code", typeof(String));
                t.Columns.Add("Original Estimate", typeof(Decimal));
                t.Columns.Add("Approved Owner Changes", typeof(Decimal));
                t.Columns.Add("Total Estimate", typeof(Decimal));
                t.Columns.Add("Job-To-Date Costs", typeof(Decimal));
                t.Columns.Add("% Complete", typeof(Decimal));
                t.Columns.Add("Cost To Complete", typeof(Decimal));
                t.Columns.Add("Revised Cost At Completion", typeof(Decimal));
                t.Columns.Add("Total Estimate Variance", typeof(Decimal));
    
                //Row Added Here
    
                DataView dvbc = new DataView(t);
                DataGrid dgbc = new System.Windows.Controls.DataGrid();
                dgbc.ItemsSource = dvbc;
                TreeViewItem tvbc = new TreeViewItem() { Header = dgbc };
                tvbc.UpdateLayout();
                if (mat.first != null)
                {
                    DataTable ct = new DataTable();
                    ct.Columns.Add("Category", typeof(String));
                    ct.Columns.Add("Original Estimate", typeof(Decimal));
                    ct.Columns.Add("Approved Owner Changes", typeof(Decimal));
                    ct.Columns.Add("Total Estimate", typeof(Decimal));
                    ct.Columns.Add("Job-To-Date Costs", typeof(Decimal));
                    ct.Columns.Add("% Complete", typeof(Decimal));
                    ct.Columns.Add("Cost To Complete", typeof(Decimal));
                    ct.Columns.Add("Revised Cost At Completion", typeof(Decimal));
                    ct.Columns.Add("Total Estimate Variance", typeof(Decimal));
    
                    //Row Added Here
    
                    ct.AcceptChanges();
                    DataView dv = new DataView(ct);
                    DataGrid dg = new System.Windows.Controls.DataGrid();
                    dg.ItemsSource = dv;
                    TreeViewItem tvi = new TreeViewItem() { Header = dg };
                    tvi.UpdateLayout();
                    tvbc.Items.Add(tvi);
                    if (mat.first.next != null)
                    {
                        mat = mat.first;
                        Boolean myHeader = true;
                        while (mat.next != null)
                        {
                            mat = mat.next;
                            DataTable ctch = new DataTable();
                            ctch.Columns.Add("Category", typeof(String));
                            ctch.Columns.Add("Original Estimate", typeof(Decimal));
                            ctch.Columns.Add("Approved Owner Changes", typeof(Decimal));
                            ctch.Columns.Add("Total Estimate", typeof(Decimal));
                            ctch.Columns.Add("Job-To-Date Costs", typeof(Decimal));
                            ctch.Columns.Add("% Complete", typeof(Decimal));
                            ctch.Columns.Add("Cost To Complete", typeof(Decimal));
                            ctch.Columns.Add("Revised Cost At Completion", typeof(Decimal));
                            ctch.Columns.Add("Total Estimate Variance", typeof(Decimal));
    
                            //Row Added Here
    
                            ctch.AcceptChanges();
                            DataView dvc = new DataView(ctch);
                            DataGrid dgc = new System.Windows.Controls.DataGrid();
                            dgc.ItemsSource = dvc;
                            TreeViewItem tvic = new TreeViewItem() { Header = dgc };
                            tvic.UpdateLayout();
                            tvi.Items.Add(tvic);
                         }
                      }
                   }
                }
    
                //This if statement is repeated 5 more times for other Children of tvi.  That code is Identical to what is shown here(omitted Row add is different).
    
                //This is the end of the relevant code
    

Прошу прощения за образец длинного кода.

Итак, моя проблема в том, что все это происходит в конструкторе для окна. В конце области действия переменной DataGrid у нее нет столбцов, которые мне нужны для форматирования столбцов для правильного выравнивания. Однако, когда событие запускается из DataGrid, и я получаю количество столбцов от отправителя, который был передан в DataGrid, он отображается как имеющий 9 столбцов (правильное число)

Я попытался использовать события AutoGeneratingColumn и AutoGeneratedColumns, чтобы узнать, когда DataGrid инициализировал свои столбцы, и события никогда не срабатывали.

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

Спасибо за ваше время.


person rClark    schedule 19.03.2014    source источник
comment
RE Мысль 1: datatable -> dataview -> datagrid был единственным способом, которым я мог отобразить это, как на картинке (это идеальный вид для того, что мы пытаемся сделать). Я новичок в wpf, и если у вас есть лучшее предложение, я весь слушаю.   -  person rClark    schedule 20.03.2014
comment
WPF поддерживает DataBinding для правильных строго типизированных объектов CLR. забудьте DataTable. Это из .Net 1.1   -  person Federico Berasategui    schedule 20.03.2014
comment
Кстати, нет, это не идеальный вид, независимо от того, что вы пытаетесь сделать, этот чрезмерно загроможденный пользовательский интерфейс действительно плох с точки зрения взаимодействия с пользователем.   -  person Federico Berasategui    schedule 20.03.2014
comment
RE Мысль 2: ни одна из этих частей окна не использует winforms (буквально вопрос в том, что парень предпочитает окно сообщений winforms, поэтому обертывание элементов управления не требуется). Я изучаю wpf на лету, так как это был единственный способ получить функциональность DataGrid и TreeView вместе. Если есть статья, о которой вы знаете, с примерами кода о том, как реализовать правильную привязку данных в моем классе объектов, я был бы очень признателен за точку в правильном направлении. Я искал такие статьи и не смог найти ни одной, которую мог бы успешно воспроизвести.   -  person rClark    schedule 20.03.2014
comment
Я склонен согласиться с идеальным внешним видом, однако это было то, о чем меня просили.   -  person rClark    schedule 20.03.2014
comment
RE Мысль 3: для дальнейшего использования, можете ли вы определить приблизительный подсчет размера коллекции, когда в игру не вступает никакой надежды?   -  person rClark    schedule 20.03.2014


Ответы (1)


Вы действительно не должны делать такие вещи в коде. Гораздо проще, если вы определите свой DataGrid.Columns в XAML, привяжете данные к свойству DataGrid.ItemsSource и просто обновите связанную коллекцию данных из кода. Вы можете легко выровнять DataGridTextColumn по правому краю в XAML следующим образом:

<DataGridTextColumn Binding="{Binding SomeNumericColumn}">
    <DataGridTextColumn.ElementStyle>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="HorizontalAlignment" Value="Right" />
        </Style>
    </DataGridTextColumn.ElementStyle>
</DataGridTextColumn> 

ОБНОВЛЕНИЕ >>>

Style можно использовать повторно, но обычно мы определяем каждый из столбцов в DataGrid:

<Style Name="RightAlign" TargetType="{x:Type TextBlock}">
    <Setter Property="HorizontalAlignment" Value="Right" />
</Style>

...

<DataGrid.Columns>
    <DataGridTextColumn Binding="{Binding SomeTextColumn}" />
    <DataGridTextColumn Binding="{Binding SomeNumericColumn}"
        ElementStyle="{StaticResource RightAlign}" ... />
    <DataGridTextColumn Binding="{Binding AnotherTextColumn}" />
    ...
</DataGrid.Columns>
person Sheridan    schedule 19.03.2014
comment
Спасибо за ответ. Я новичок (менее года) в разработке интерфейсов (я создаю решения от концепции до выпуска и поддержки, поэтому даже часть этого была связана с интерфейсами, тогда как раньше я только проектировал и разрабатывал внутренние структуры), и из-за этого я до сих пор на самом деле у вас пока нет концептуальных возможностей XAML. Будет ли это шаблон в XAML, который я бы установил для DataGridColumn, или мне придется делать это в XAML для каждого возможного DataGridColumn, который может быть создан динамически? - person rClark; 20.03.2014