Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.83/6: Рейтинг темы: голосов - 6, средняя оценка - 4.83
 Аватар для xellan24rus
364 / 296 / 55
Регистрация: 08.04.2020
Сообщений: 1,175

Привязка свойства колонки DataGrid к триггеру элемента ячейки

01.09.2024, 04:07. Показов 1968. Ответов 29
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Дорого времени суток и с днем знаний всех =)
У меня имеется DataGrid с классом "DataGridTextColumnApp" который наследуется от "DataGridTextColumn" в нем я добавил свойство "IsFirst" оно нужно чтобы определять является столбец первым, если да, то тригер должен срабатывать.
Вариант кода сокращен до рамок вопроса, поэтому сам код выглядит бессмысленным, но на деле это нужно
Проблема в привязках тригеров стилей: "CustomTextBlockStyle" и "CustomDataGridColumnHeaderStyle" они не срабатывают.
(В CustomTextBlockStyle сделал через Tag-работает, но тоже хотелось бы использовать привязку, без Tag)


Итак класс DataGridTextColumnApp
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 public class DataGridTextColumnApp : DataGridTextColumn
  {
      public bool IsFirst
      {
          get { return (bool)GetValue(IsFirstProperty); }
          set { SetValue(IsFirstProperty, value); }
      }
 
      public static readonly DependencyProperty IsFirstProperty =
          DependencyProperty.Register("IsFirst", typeof(bool), typeof(DataGridTextColumnApp), new FrameworkPropertyMetadata(false) { BindsTwoWayByDefault = true });
 
      protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
      {
          TextBlock editingElement = new TextBlock();
          editingElement.SetBinding(TextBlock.TextProperty, base.Binding);
          editingElement.Style = (Style)cell.FindResource("CustomTextBlockStyle");
          return editingElement;
      }
 
      protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
      {
          TextBlock readonlyTextBox = new TextBlock();
          BindingOperations.SetBinding(readonlyTextBox, TextBlock.TextProperty, base.Binding);
          readonlyTextBox.Style = (Style)cell.FindResource("CustomTextBlockStyle");
          readonlyTextBox.Tag = this; // Костыль ибо не смог указать привязку.
          base.HeaderStyle = (Style)cell.FindResource("CustomDataGridColumnHeaderStyle");
 
          return readonlyTextBox;
      }
  }
wpf

XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<Window x:Class="SampleGrid.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SampleGrid"
        xmlns:sys="clr-namespace:System;assembly=System.Runtime"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <x:Array x:Key="Data" Type="{x:Type sys:String}">
            <sys:String>1111</sys:String>
            <sys:String>1111</sys:String>
            <sys:String>1111</sys:String>
            <sys:String>1111</sys:String>
            <sys:String>1111</sys:String>
            <sys:String>1111</sys:String>
        </x:Array>
 
        <Style x:Key="CustomDataGridColumnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}">
            <Setter Property="Margin" Value="0,0,0,0" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=local:DataGridTextColumnApp}, Path=IsFirst}" Value="True">
                    <Setter Property="Margin" Value="30 0 0 0"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
 
        <Style x:Key="CustomTextBlockStyle" TargetType="{x:Type TextBlock}">
            <Setter Property="Margin" Value="0,0,0,0" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Tag.IsFirst, RelativeSource={RelativeSource Self}}" Value="True">
                    <Setter Property="Margin" Value="30 0 0 0"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <DataGrid Margin="100"
                  AutoGenerateColumns="False"
                  ItemsSource="{StaticResource Data}">
            <DataGrid.Columns>
                <local:DataGridTextColumnApp Width="*" 
                                             Header="Имя" 
                                             IsFirst="True"
                                             HeaderStyle="{StaticResource CustomDataGridColumnHeaderStyle}" ElementStyle="{StaticResource CustomTextBlockStyle}" 
                                             Binding="{Binding }"/>
            </DataGrid.Columns>
        </DataGrid>
 
    </Grid>
</Window>
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
01.09.2024, 04:07
Ответы с готовыми решениями:

Привязка отдельных данных к combobox из листа колонки DataGrid
Всем привет! :) Помогите решить задачу, в общем есть класс Teacher, который используется для привязки в DataGrid. Класс имеет следующую...

Как сделать правильную привязку колонки свойства Visibility в DataGrid?
Есть некоторые колонки в Datagrid: &lt;DataGridTextColumn Header=&quot;Дата партии&quot; ...

Привязка элемента к datagrid
http://msdn.microsoft.com/ru-ru/library/ff407126.aspx - вот здесь есть статья, по ней все получается, но у меня есть одно отличие. В статье...

29
 Аватар для xellan24rus
364 / 296 / 55
Регистрация: 08.04.2020
Сообщений: 1,175
05.09.2024, 16:45  [ТС]
Студворк — интернет-сервис помощи студентам
Элд Хасп, спасибо большое, теперь все как часики работает
0
 Аватар для xellan24rus
364 / 296 / 55
Регистрация: 08.04.2020
Сообщений: 1,175
15.09.2024, 17:12  [ТС]
Элд Хасп, подскажите еще с привязкой одного свойства. Попробовал сделать как у вас, но похоже не разобрался.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
 public static class DataGridCellHelper
  {
      static DataGridCellHelper()
      {
          EventManager.RegisterClassHandler(typeof(DataGridCell), FrameworkElement.SizeChangedEvent, OnLoaded, true);
          EventManager.RegisterClassHandler(typeof(DataGridColumnHeader), FrameworkElement.SizeChangedEvent, OnLoaded, true);
      }
 
      public static readonly DependencyProperty IsFirstProperty =
          DependencyProperty.RegisterAttached(
              nameof(IsFirstProperty)[0..^8],
              typeof(bool),
              typeof(DataGridCellHelper),
              new FrameworkPropertyMetadata(false)
              {
                  BindsTwoWayByDefault = true,
              });
 
      public static bool GetIsFirst(DependencyObject obj)
      {
          return (bool)obj.GetValue(IsFirstProperty);
      }
 
      public static void SetIsFirst(DependencyObject obj, bool value)
      {
          obj.SetValue(IsFirstProperty, value);
      }
 
 
      #region IsActualWidth
      public static readonly DependencyProperty IsActualWidthProperty =
                  DependencyProperty.RegisterAttached(
                      "IsActualWidth",
                      typeof(double),
                      typeof(DataGridCellHelper),
                      new FrameworkPropertyMetadata((double)0));
      private static void SetIsActualWidth(DependencyObject element, double value) => element.SetValue(IsActualWidthProperty, value);
 
      public static double GetIsActualWidth(DependencyObject element) => (double)element.GetValue(IsActualWidthProperty);
      #endregion
 
 
      private static readonly Binding CellColumnIsFirstBinding = new Binding()
      {
          Path = new PropertyPath("(0).(1)", DataGridCell.ColumnProperty, IsFirstProperty),
          RelativeSource = RelativeSource.Self
      };
 
      private static readonly Binding HeaderColumnIsFirstBinding = new Binding()
      {
          Path = new PropertyPath("(0).(1)", typeof(DataGridColumnHeader).GetProperty(nameof(DataGridColumnHeader.Column)), IsFirstProperty),
          RelativeSource = RelativeSource.Self
      };
 
      private static readonly Binding IsActualWidthColumnBinding = new Binding()
      {
          Path = new PropertyPath("(0).(1)", typeof(DataGridColumnHeader).GetProperty(nameof(DataGridColumnHeader.Column)), IsActualWidthProperty),
          RelativeSource = RelativeSource.Self
      };
 
      private static readonly Binding CellIsFirstBinding = new Binding()
      {
          Path = new PropertyPath("(0)", IsFirstProperty),
          RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(DataGridCell), 1)
      };
      private static readonly Binding HeaderIsFirstBinding = new Binding()
      {
          Path = new PropertyPath("(0)", IsFirstProperty),
          RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(DataGridColumnHeader), 1)
      };
 
      private static readonly Binding HeaderIsActualWidthBinding = new Binding()
      {
          Path = new PropertyPath("(0)", IsActualWidthProperty),
          RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(DataGridColumnHeader), 1)
      };
 
      private static readonly RoutedEventHandler OnLoaded = async (sender, e) =>
      {
          FrameworkElement element = (FrameworkElement)sender;
          Binding binding = null;
          Binding bindingWidth = null;
          switch (element)
          {
              case DataGridCell:
                  binding = CellColumnIsFirstBinding;
                  break;
              case DataGridColumnHeader:
                  binding = HeaderColumnIsFirstBinding;
                  bindingWidth = IsActualWidthColumnBinding;
                  element.SetBinding(IsActualWidthProperty, bindingWidth);
                  break;
          }
 
          element.SetBinding(IsFirstProperty, binding);
 
          DependencyPropertyDescriptor descriptorDpContent = DependencyPropertyDescriptor.FromProperty(ContentControl.ContentProperty, element.GetType());
          descriptorDpContent.AddValueChanged(element, OnContentChanged);
          OnContentChanged(element, EventArgs.Empty);
      };
 
      private static void OnContentChanged(object? sender, EventArgs e)
      {
          ArgumentNullException.ThrowIfNull(sender);
          ContentControl control = (ContentControl)sender;
 
          DependencyObject? dobj = null;
          if (control.Content is UIElement uie)
          {
              dobj = uie;
              if (dobj is ContentPresenter cp)
              {
                  dobj = cp.GetChildren().Skip(1).FirstOrDefault();
              }
          }
          else if (control.GetFirstChild<ContentPresenter>() is ContentPresenter cp)
          {
              dobj = cp.GetChildren().Skip(1).FirstOrDefault();
          }
 
          if (dobj is not null)
          {
              Binding binding = null;
              Binding bindingWidth = null;
              switch (control)
              {
                  case DataGridCell:
                      binding = CellIsFirstBinding;
                      break;
                  case DataGridColumnHeader:
                      binding = HeaderIsFirstBinding;
                      bindingWidth = HeaderIsActualWidthBinding;
                      BindingOperations.SetBinding(control, IsActualWidthProperty, bindingWidth);
                      if (dobj is TextBlock textBlock)
                          SetIsActualWidth(control, textBlock.ActualWidth);
                      break;
              }
              BindingOperations.SetBinding(dobj, IsFirstProperty, binding);
          }
      }
  }
Использование
C#
1
2
3
4
5
6
7
8
9
 private static ObservableCollection<DataGridColumn> ListColumns;
 private static void DataGridInitColumns(object sender, RoutedEventArgs e)
 {
     if (sender is DataGrid dataGrid)
     {
         ListColumns = dataGrid.Columns;
 
     }
 }
И так хочу получить ширину заголовков.
C#
1
2
3
4
5
6
7
8
 for (int i = 1; i <= ListColumns.Count; i++)
 {
     if(current_width <= total_width && (current_width += 90) < total_width)
     {
         total_element++;
         var width= DataGridCellHelper.GetIsActualWidth(ListColumns[i]); // Всегда 0...
     }
 }
Добавлено через 55 секунд
Свойство IsActualWidth добавил, чтобы можно было привязать ширину заголовка

Добавлено через 1 минуту
В OnLoaded и OnContentChanged сделал привязку.
Указываю значение в OnContentChanged
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
15.09.2024, 17:31
Цитата Сообщение от xellan24rus Посмотреть сообщение
Свойство IsActualWidth добавил, чтобы можно было привязать ширину заголовка
Объясните логику зависимости.
И почему "Is...", но свойство double ?
0
 Аватар для xellan24rus
364 / 296 / 55
Регистрация: 08.04.2020
Сообщений: 1,175
15.09.2024, 17:42  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
И почему "Is...", но свойство double ?
Это хорошее замечание. Позже сменю имя на нормальное.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Объясните логику зависимости.
Логика свойства в том чтобы получать ширину заголовка столбца.


В остальном логика такая, подсчет ширины datagrid > отображение столбцов которые возможно отобразить на экране.
К примеру на полном экране отобразить все столбцы, а в нормальном состояние только половину.
Я понимаю что можно использовать горизонтальный скрол для этой задачи, но в текущей реализации он не подходит. И поэтому все расчеты касательно элементов.
И количество столбцов можно представить как страницы. Где на первой странице может быть 8 столбцов, на второй 9 и т.п
Так сказать иная навигация..

Добавлено через 2 минуты
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Объясните логику зависимости.
сейчас ее задаю так
C#
1
2
3
4
5
6
7
 case DataGridColumnHeader:
                      binding = HeaderIsFirstBinding;
                      bindingWidth = HeaderIsActualWidthBinding;
                      BindingOperations.SetBinding(control, IsActualWidthProperty, bindingWidth);
                      if (dobj is TextBlock textBlock)
                          SetIsActualWidth(control, textBlock.ActualWidth);
                      break;
Но получить не могу значение
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
15.09.2024, 17:49
Цитата Сообщение от xellan24rus Посмотреть сообщение
Логика свойства в том чтобы получать ширину заголовка столбца.
Чем ширина заголовка отличается от ширины колонки и ячеек в ней?
0
 Аватар для xellan24rus
364 / 296 / 55
Регистрация: 08.04.2020
Сообщений: 1,175
15.09.2024, 18:15  [ТС]
Элд Хасп, к примеру в ListColumns[3] ширина 69.
А
C#
1
SetIsActualWidth(control, textBlock.ActualWidth);
ширина 59
А столбец один и тот же.

Добавлено через 15 минут
Элд Хасп, хотя как я выяснил я не правильно считаю саму таблицу, шаблон сильно изменен у меня, много кода.
Вместо заявленного 732 по ширине, DataGridColumnHeadersPresenter у меня 672, а это нужная область. Из за разницы и были проблемы с шириной столбцов.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
15.09.2024, 18:26
Цитата Сообщение от xellan24rus Посмотреть сообщение
Из за разницы и были проблемы с шириной столбцов.
Решили?
0
 Аватар для xellan24rus
364 / 296 / 55
Регистрация: 08.04.2020
Сообщений: 1,175
15.09.2024, 18:31  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Решили?
По времени поздно уже ( Завтра на работу, рано. После работы, в более свободное время буду пробовать.
На старом коде работало как мне нужно, не считая лишнего столбца. Но как выяснилось из за DataGridColumnHeadersPresenter как раз таки рабочая область у меня выходит меньше. А ширина таблицы чуть больше.
Поэтому думаю что решил этот вопрос, но нужно переписывать код опять и все расчеты для отображения столбцов
Должно получиться как страничная навигация для определенного кол-ва столбцов, переключение кнопками, изменение от размера приложения. Что то по типу скрола, но без него и чутка умнее, малость.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
15.09.2024, 19:02
Цитата Сообщение от xellan24rus Посмотреть сообщение
Что то по типу скрола, но без него и чутка умнее, малость.
Почему скрулл не кастомизировать?

Добавлено через 8 минут
Хотя это тоже весьма не просто, но как-то больше в тему будет.
0
 Аватар для xellan24rus
364 / 296 / 55
Регистрация: 08.04.2020
Сообщений: 1,175
15.09.2024, 19:12  [ТС]
Элд Хасп, скрол вмещает в себя контент и уже от конечного размера дает прокрутку.
Если судить про смещения по офсетам, то для скрола нужен весь контент.. К примеру у меня столбец не влазит в таблицу на 20-30 пикселей что портит всю картинку, то есть этот столбец будет только на половину отображен или его часть. Я скрою этот столбец, отлично. Но следом появится новый столбец и он будет в той же зоне...

Из вариантов для скрола тогда написать ap и для кнопок таблицы. Поэтому решил делать ap для самой таблицы, которая будет управлять видимостью столбцов, ну пару кнопок для перелистывания "страниц"

И так как размер DataGridColumnHeadersPresenter является у меня рабочей областью для подсчета нужных столбцов, то размер скрола мне не подошел бы. Ведь он был бы равен, размеру таблицы. А этот размер у меня сейчас больше, он и должен быть больше. Так как в DataGridColumnHeadersPresenter у меня свои изменения.

Добавлено через 1 минуту
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Хотя это тоже весьма не просто, но как-то больше в тему будет.
Как по мне в реализации одинаково приятно. Отличие только в том, куда добавлять ap, и как потом получать нужные размеры.
К примеру в скроле скрыть столбец уже чуть затратнее, ведь надо получать доступ к таблице. А имея все нужные размеры, в самой таблице через ap можно видимостью управлять как угодно.

Добавлено через 2 минуты
Да и анимация прокрутки уже готова, правда вышло чутка криво Но слабо заметно, поэтому я не доволен. Потом буду фиксить.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
15.09.2024, 19:12

как получить значения строки и колонки выбранной ячейки DataGrid в MultiBinding?
В меня есть DataGrid и кнопка. У кнопки стоить MultiBinding. Нужно, чтобы в него помешались строка и столбец выбранной ячейки DataGrid....

Изменить значение свойства элемента с типом E (привязка к элементам)
Здравствуйте. Вопрос следующий. Я пытаюсь изменить свойства инфоблока через CIBlockElement::SetPropertyValuesEx. Для всех свойств...

Привязка элемента диаграммы к значению ячейки
Есть ячейка, которая хранит значение выбранного элемента списка. Необходимо чтобы при выборе другого элемента, диаграмма , которая ...

Как забиндить через код, чтоб при изменении свойства изменялся цвет ячейки в DataGrid
Если бы привязка делалась через XAML, то вопросов нет, все получается, но не могу понять как привязать это через код. Суть в следующем....

Можно ли в DataGrid поменять свойства определённого элемента управления?
Можно ли в DataGrid поменять свойства определённого элемента управления, вставленного в грид-таблицу в качестве &lt;asp:TemplateColumn&gt; ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
30
Ответ Создать тему
Новые блоги и статьи
Nekobox - outbounds[0].transport: unknown transport type: raw
damix 01.10.2026
Фикс ошибки Правым кликом по серверу -> отладочная информация -> edit Заменить "net": "raw", на "net": "tcp", Нажать кнопку reload.
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru