0

I have a requirement where on one DataGrid column, I need to show x number of clickable buttons side by side (horizontally stacked). The actual number or buttons to show depends on the binded value in that column.

The image below shows this. The left hand grid is my current one and and the right hand grid is what I am looking for.

Current and desired DataGrid

Grid is binded to ViewModel like:

<DataGrid ItemsSource="{Binding employees}" AutoGenerateColumns="False"  >
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Path=id}" Header="Id" />
            <DataGridTextColumn Binding="{Binding Path=numberofplatforms}" Header="No" Width="50" IsReadOnly="True" />
        </DataGrid.Columns>
    </DataGrid>

And ViewModel is:

Public Class ViewModel

    Public Property employees As ObservableCollection(Of employee)
        Get
            Return _employees
        End Get
        Set(ByVal value As ObservableCollection(Of employee))
            _employees = value
        End Set
    End Property
    Private _employees As New ObservableCollection(Of employee)

End Class

And the employee is:

Public Class employee
    Public Property id As String
    Public Property numberofplatforms As Integer
    Public Property selectedplatform As Integer
End Class

On top of just displaying the buttons, the buttons themselve must act like radiobuttons, i.e. on any DataGrid row, only one button is "pushed down" (blue background buttons in the image) and the others are not pushed (gray background). Buttons (or shapes) must be clickable so that the selection can be changed.

Which button is "pushed" down is determined from the ViewModel, according to selectedplatform property. That property in this example is 1 for the ABC, 1 for the DEF and 2 for the GHI. If the numberofplatforms property is zero, no buttons are displayed (JKL).

How can I set up this mechanism?

1 Answer 1

3

Some parts of the code are in C#, I hope it's not a problem. Wpf code:

<Window.Resources>
    <ResourceDictionary>
        <local:PositiveIntegersConverter x:Key="PositiveIntegersConverter" />
        <local:EmployeePlatformOptionConverter x:Key="EmployeePlatformOptionConverter"/>
    </ResourceDictionary>
</Window.Resources>

<DataGrid ItemsSource="{Binding employees}" AutoGenerateColumns="False" x:Name="DataGrid1">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Path=id}" Header="Id" />
        <DataGridTemplateColumn Header="No" IsReadOnly="True">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                        <ListBox ItemsSource="{Binding numberofplatforms, Converter={StaticResource PositiveIntegersConverter}}" SelectedItem="{Binding selectedplatform}"
                                    x:Name="ListBox1">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <Button Content="{Binding}" Command="{Binding Source={x:Reference DataGrid1}, Path=DataContext.SelectOptionCommand}">
                                        <Button.CommandParameter>
                                            <MultiBinding Converter="{StaticResource EmployeePlatformOptionConverter}">
                                                <Binding ElementName="ListBox1" Path="DataContext"/>
                                                <Binding Path="."/>
                                            </MultiBinding>
                                        </Button.CommandParameter>
                                        <Button.Style>
                                            <Style TargetType="Button">
                                                <Setter Property="Background" Value="Gray" />
                                                <Setter Property="Foreground" Value="White" />
                                                <Style.Triggers>
                                                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBoxItem}, Path=IsSelected}"
                                                                    Value="True">
                                                        <Setter Property="Background" Value="Blue" />
                                                    </DataTrigger>
                                                </Style.Triggers>
                                            </Style>
                                        </Button.Style>
                                    </Button>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                            <ListBox.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <StackPanel Orientation="Horizontal" />
                                </ItemsPanelTemplate>
                            </ListBox.ItemsPanel>
                        </ListBox>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

I used two converters here:

PositiveIntegersConverter which returns positive integers for a given numberofplatforms - these are available platform options for an employee

EmployeePlatformOptionConverter which converts two parameters that we want to pass to SelectOptionCommand: employee and selected platform option into one object of EmployeePlatformOption type.

public class PositiveIntegersConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var toInteger = System.Convert.ToInt32(value);
        return toInteger > 0 ? Enumerable.Range(1, toInteger) : null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

public class EmployeePlatformOptionConverter
    : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return new EmployeePlatformOption
            {
                Employee = values[0] as Employee,
                Platform = (int)values[1]
            };
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Using encapsulating object:

public class EmployeePlatformOption
{
    public Employee Employee { get; set; }
    public int Platform { get; set; }
}

you pass selection to SelectOptionCommand in your ViewModel class:

public ICommand SelectOptionCommand { get; set; }
private void SelectOptionExecute(EmployeePlatformOption employeePlatformOption)
{
    if (employeePlatformOption != null && employeePlatformOption.Employee != null &&
        employeePlatformOption.Platform > 0)
    {
        employeePlatformOption.Employee.selectedplatform = employeePlatformOption.Platform;
    }
}

Employee should implement INotifyPropertyChange interface so selectedplatform update is visible on the screen.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.