Christian Tang
Christian Tang

Reputation: 1450

Make first row of DataGrid ReadOnly

I'm using a DataGrid to display user permissions in my WPF-application.

The first row of the DataGrid will always contain the owner of the project for which the permissions are displayed.

This owner is set when the project is created and can not be changed directly from the DataGrid.

My question then is.

How can I make the first row ReadOnly, and maybe give it a specific style so the background can be changed?

Upvotes: 1

Views: 4681

Answers (2)

user572559
user572559

Reputation:

Here's my take on it. The previous sample will do you just fine, my sample is for demonstration of the approach for acquiring low level control over the cells look. In WPF DataGridRow is just a logical container, you can only use 'attached' properties with it, such as Enabled, FontSize, FontWeight etc., as they'll get propagated down to the cell level), but the actual control's look is defined at a cell level.

TextBlock's for readonly stuff generally look cleaner than disabled texboxes, also you might want to apply completely different style for readonly and editable modes of your cells, for which you'll have to do somewhat similar to what the code below does.

Code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ReadOnlyRows
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.Loaded += (o, e) =>
            {
                this.g.ItemsSource = new List<Person>(2)
                {
                    new Person(){ Name="Dmitry", Role="Owner" },
                    new Person(){ Name="Jody", Role="BA" }
                };
            };
        }
    }

    public class Person
    {
        public string Role
        {
            get;
            set;
        }

        public string Name
        {
            get;
            set;
        }
    }

    public class PersonServices
    {
        // that shouldn't be in template selector, whould it?
        public static bool CanEdit(Person person)
        {
            return person.Role != "Owner";
        }
    }

    public class TemplateSelector : DataTemplateSelector
    {
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            Person person = item as Person;

            if (person == null) return null;

            string templateName = PersonServices.CanEdit(person) ? "EditableDataTemplate" : "ReadOnlyDataTemplate";

            return (DataTemplate)((FrameworkElement)container).FindResource(templateName);
        }
    }

    public class EditingTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            Person person = item as Person;

            if (person == null) return null;

            string templateName = PersonServices.CanEdit(person) ? "EditableEditingDataTemplate" : "ReadOnlyEditingDataTemplate";

            return (DataTemplate)((FrameworkElement)container).FindResource(templateName);
        }
    }
}

XAML:

<Window x:Class="ReadOnlyRows.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ReadOnlyRows"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid x:Name="g" AutoGenerateColumns="False"
                  CanUserAddRows="False">
            <DataGrid.Resources>
                <DataTemplate x:Key="EditableEditingDataTemplate">
                    <TextBox Text="{Binding Name}" />
                </DataTemplate>

                <DataTemplate x:Key="ReadOnlyEditingDataTemplate">
                    <TextBlock Text="{Binding Name}" FontWeight="Bold" />
                </DataTemplate>

                <DataTemplate x:Key="EditableDataTemplate">
                    <TextBlock Text="{Binding Name}" />
                </DataTemplate>

                <DataTemplate x:Key="ReadOnlyDataTemplate">
                    <TextBlock Text="{Binding Name}" FontWeight="Bold" />
                </DataTemplate>

                <local:TemplateSelector x:Key="TemplateSelector" />
                <local:EditingTemplateSelector x:Key="EditingTemplateSelector" />
            </DataGrid.Resources>

            <DataGrid.Columns>
                <DataGridTemplateColumn Header="Name"
                    CellTemplateSelector="{StaticResource TemplateSelector}"
                    CellEditingTemplateSelector="{StaticResource EditingTemplateSelector}" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

Upvotes: 1

emybob
emybob

Reputation: 1333

You will need a trigger for this, the only problem is that getting a row index on the wpf datagrid is pretty awful, so i tend to do something like this:

    <DataGrid.RowStyle>
            <Style TargetType="DataGridRow">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=IsOwner}" Value="true">
                        <Setter Property="IsEnabled" Value="False"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </DataGrid.RowStyle>

where there's a property value on the object i know will be unique to that particular row. So if there's a unique ID or something that the owner always has, you can bind to that.

The setter property is 'IsEnabled' as datagridrow doesn't contain a property for readonly, but this will stop a user modifying the row.

Upvotes: 6

Related Questions