1

Попробовал реализовать свою задумку самостоятельно, но упёрся в тупик. Вот, что имею в проекте.

Использую DataGrid для отображения данных. Он в свою очередь находится внутри кастомного UserControl, в который также с помощью привязок поставляются поставляются коллекции данных типа ObservableCollection<string>.

Table.xaml

<UserControl>
     <!--...-->
     <DataGrid SelectionMode="Single" AutoGenerateColumns="False" CanUserReorderColumns="False" ColumnWidth="*" CanUserAddRows="False" CanUserDeleteRows="False" SelectionUnit="Cell">
         <DataGrid.Columns>
             <dgc:DataGridTextColumnWithCollection ColumnDataCollection="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}}, Path=Collection1}"/>
             <dgc:DataGridTextColumnWithCollection ColumnDataCollection="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}}, Path=Collection2}"/>
             ...
         </DataGrid.Columns>
     </DataGrid>
     <!--...-->
</UserControl>

Table.xaml.cs

public partial class Table : UserControl
{
    //...
    public static readonly DependencyProperty Collection1Property = DependencyProperty.Register(
        "Collection1",
        typeof(ObservableCollection<string>),
        typeof(Table),
        new FrameworkPropertyMetadata(null, null, null));
public ObservableCollection&lt;string&gt; Collection1
{
    get { return (ObservableCollection&lt;string&gt;)GetValue(Collection1Property); }
    set { SetValue(Collection1Property, value); }
}

public static readonly DependencyProperty Collection2Property = DependencyProperty.Register(
    &quot;Collection2&quot;,
    typeof(ObservableCollection&lt;string&gt;),
    typeof(Table),
    new FrameworkPropertyMetadata(null, null, null));

public ObservableCollection&lt;string&gt; Collection2
{
    get { return (ObservableCollection&lt;string&gt;)GetValue(Collection2Property); }
    set { SetValue(Collection2Property, value); }
}
//...

}

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

DataGridTextColumnWithCollection.cs

public class DataGridTextColumnWithCollection : DataGridTextColumn
    {
        public static readonly DependencyProperty ColumnDataCollectionProperty = DependencyProperty.Register(
            "ColumnDataCollection",
            typeof(ObservableCollection<string>),
            typeof(DataGridTextColumnWithCollection),
            new FrameworkPropertyMetadata(null, null, null));
    public ObservableCollection&lt;string&gt; ColumnDataCollection
    {
        get { return (ObservableCollection&lt;string&gt;)GetValue(ColumnDataCollectionProperty); }
        set { SetValue(ColumnDataCollectionProperty, value); }
    }
}

И, наконец, в шаблоне DataGridCell к нему приписан Popup с ListBox, который является конечной точкой в цепи привязок

CustomDataGrid.xaml

<ResourceDictionary>
    <!--...-->
    <Style TargetType="{x:Type DataGridCell}">
    <Setter Property="Template">
    <Setter.Value>
    <ControlTemplate TargetType="{x:Type DataGridCell}">
        <Border>
        <Grid>
            <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
            <Popup Focusable="False" PopupAnimation="Slide">
                <Grid x:Name="DropDown" SnapsToDevicePixels="True" Width="{TemplateBinding ActualWidth}">
                    <ListBox ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGridCell}}, Path=Column.ColumnDataCollection}"/>
                </Grid>
            </Popup>
        </Grid>
        </Border>
    </ControlTemplate>
    </Setter.Value>
    </Setter>
    </Style>
    <!--...-->
</ResourceDictionary>

Суть моей задачи - добиться того, чтобы в Popup-элементе у каждой DataGridCell отображался набор элементов, в зависимости от того, в каком столбце находится клетка. Эти элементы никак не зависят от Item-ов самого DataGrid-а и не являются ими или их частью.

Вышеописанная попытка с цепью привязок и кастомным свойством зависимости у столбца не сработала. Точно не понимаю, в каком месте происходит сбой, однако сильнее всего меня смущает эта привязка (CustomDataGrid.xaml):

<ListBox ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGridCell}}, Path=Column.ColumnDataCollection}"/>

Поэтому, буду рад как определению ошибок в моём решении, так и предложенным альтернативам решению задачи с коллекциями у клеток в зависимости от колонок.

upd 1. Вот источник данных, к которым привяжутся свойства UserControl-a:

public class ViewModel : BaseViewModel
{
    // ...
    public ViewModel ()
    {
        Source1 = new ObservableCollection<string>();
        Source2 = new ObservableCollection<string>();
        Source1.Add("стол");
        Source1.Add("шкаф");
        Source2.Add("белый");
        Source2.Add("красный");
    }
public ObservableCollection&lt;string&gt; Source1 { get; set; }
public ObservableCollection&lt;string&gt; Source2 { get; set; }
// ...

}

И примерно такого результата хочу добиться:

Popup клетки с коллекцией строк

Lucifer
  • 13
  • А вы без попапа и юзерконтрола для начала смогли этого добиться? Или я не понял, что такое попап. – aepot Apr 06 '21 at 15:25
  • @aepot, popup - всплывающее окно. Хочу в нём разместить коллекцию строк в зависимости от колонки, в которой находится клетка. Пробовал вывести в этот Popup свойство FontSize, которым обладает DataGridTextColumn - выводится. И в user control данные по привязкам успешно доходят. А вот на моменте с кастомной колонкой - тупик. То ли в свойство зависимости этой колонки данные не подвязываются, то ли ListBox не может эти данные получить... – Lucifer Apr 06 '21 at 18:01
  • Пока непонятно, приведите конкретный пример исходных данных, и что именно хотите увидеть в интерфейсе. – aepot Apr 06 '21 at 18:06
  • 1
    @aepot, вопрос дополнен. – Lucifer Apr 06 '21 at 18:33
  • Удалось разобраться? Если ответ был полезен, пожалуйста отметьте его принятым. – aepot Apr 08 '21 at 07:05
  • 1
    @aepot, в процессе экспериментов. Направление в сторону стандартных DataGridComboBoxColumn, скорее всего, верно. Спасибо. – Lucifer Apr 08 '21 at 14:45

1 Answers1

0

Вам просто надо изменить структуру данных.

public class DataItem
{
    public ObservableCollection<string> Source1 { get; set; }
    public ObservableCollection<string> Source2 { get; set; }
}

public class ViewModel : BaseViewModel { public ObservableCollection<DataItem> Items { get; set; }

public ViewModel ()
{
    Items = new ObservableCollection&lt;DataItem&gt;();
    DataItem data = new DataItem
    {
        Source1 = new ObservableCollection&lt;string&gt;();
        Source2 = new ObservableCollection&lt;string&gt;();
    };
    Items.Add(data);
    data.Source1.Add(&quot;стол&quot;);
    data.Source1.Add(&quot;шкаф&quot;);
    data.Source2.Add(&quot;белый&quot;);
    data.Source2.Add(&quot;красный&quot;);
}

}

И немного привести в порядок привязки.

<DataGrid ItemsSource="{Binding Items}" SelectionMode="Single" AutoGenerateColumns="False" CanUserReorderColumns="False" ColumnWidth="*" CanUserAddRows="False" CanUserDeleteRows="False" SelectionUnit="Cell">
    <DataGrid.Columns>
        <dgc:DataGridTextColumnWithCollection ColumnDataCollection="{Binding Source1}"/>
        <dgc:DataGridTextColumnWithCollection ColumnDataCollection="{Binding Source2}"/>
    </DataGrid.Columns>
</DataGrid>
<ControlTemplate TargetType="{x:Type DataGridCell}">
    <Border>
        <Grid>
            <TextBlock x:Name="Presenter" />
            <Popup Focusable="False" PopupAnimation="Slide">
                <Grid x:Name="DropDown" SnapsToDevicePixels="True" Width="{TemplateBinding ActualWidth}">
                    <ListBox ItemsSource="{Binding}" SelectedItem="{Binding Text, ElementName=Presenter}"/>
                </Grid>
            </Popup>
        </Grid>
    </Border>
</ControlTemplate>

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

Кстати попробуйте стандартную колонку DataGridComboBoxColumn, она наверное делает практически то что вам нужно, только примените свои стили к комбобоксу, или даже вкрутите свой темплейт в него, и не придется мучать саму табличку. Используйте свойство DataGridComboBoxColumn.EditingElementStyle чтобы задать стиль комбобокса.

aepot
  • 49,560