Как предотвратить переход столбца DataGridTemplateColumn в режим редактирования на основе некоторого условия?
У меня есть столбец DataGridTemplateColumn, который можно редактировать. Я хочу, чтобы пользователь мог редактировать содержимое ячейки в этом столбце только в том случае, если бизнес-объект удовлетворяет некоторому критерию. Предположим, что мой бизнес-объект реализует INotifyPropertyChanged и имеет три свойства: Name, отдел , и продажи. название иотдел являются строками, апродажи - двойником.
Я хочу, чтобы пользователь мог редактировать только значение Sales если отдел равен "рознице". Вот datagrid, который я мог бы использовать для этого:
<DataGrid ItemsSource="{Binding Path=MyTypeCollection}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name, Mode=OneTime}" IsReadOnly="True" />
<DataGridTextColumn Header="Department" Binding="{Binding Path=Department, Mode=OneTime}" IsReadOnly="True" />
<DataGridTemplateColumn Header="Sales">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Sales, Mode=TwoWay}" Visibility="{Binding Path={StaticResource ResourceKey=IsRetail}}" />
<TextBlock Text="{Binding Path=Sales, Mode=OneWay}" Visibility="{Binding Path={StaticResource ResourceKey=IsNotRetail}}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel>
<TextBox Text="{Binding Path=Sales, Mode=TwoWay}" Visibility="{Binding Path={StaticResource ResourceKey=IsRetail}}" />
<TextBlock Text="{Binding Path=Sales, Mode=OneWay}" Visibility="{Binding Path={StaticResource ResourceKey=IsNotRetail}}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Я использую панель стека с двумя текстовыми элементами. Я использую привязку в видимости текстовых элементов для переключения текстовых элементов. Если у меня есть строка со значениемDepartment , которое не является "Retail", я отображаю текстовый блок в столбцеSales независимо от того, находится ли ячейка в режиме отображения или в режиме редактирования.
Это похоже на топорное решение для меня. Есть ли какой-то способ предотвратить это? типы ячеек от входа в режим редактирования полностью? Я хочу разрешить режим редактирования только в том случае, если Отдел является "розничным". Возможно ли это?
Правка: добавление кода.
@Rachel. Спасибо за вашу помощь. Я хочу вставить весь мой код datagrid XAML, чтобы убедиться, что у меня все правильно.
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Path=Data}">
<DataGrid.Resources>
<DataTemplate x:Key="TextBoxTemplate">
<TextBox Text="{Binding Path=Sales}" />
</DataTemplate>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Department" Binding="{Binding Path=Department, Mode=OneTime}" />
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name, Mode=OneTime}" />
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ContentControl x:Name="salesControl">
<TextBlock Text="{Binding Sales}" />
</ContentControl>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Department}" Value="Retail">
<Setter TargetName="salesControl" Property="ContentTemplate" Value="{StaticResource TextBoxTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Sales}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Я почти получил это там, где я хочу. Когда я нажимаю на значение Sales
в строке Retail
, появляется текстовое поле, но в нем нет значения (см. здесь ). Я не уверен, почему он не имеет значения, потому что текстовое поле в TextBoxTemplate указывает привязку. Вы знаете, почему это происходит?
Edit: я заметил еще одну проблему с этим решением, я не могу редактировать значение в столбце Sales. Если я попытаюсь, значение возвращается к исходному значению предварительного редактирования.
3 ответа:
Я бы использовал
DataTrigger
, который переключает значение свойства, напримерTextBox.IsReadOnly
, основываясь на том, равен ли отдел "розничной торговле" или нет<Style ...> <!-- Set Default --> <Setter Property="IsReadOnly" Value="True" /> <Style.Triggers> <DataTrigger Binding="{Binding Department}" Value="Retail"> <Setter Property="IsReadOnly" Value="False" /> </DataTrigger> </Style.Triggers> </Style>
Если вам не нужно никакое другое редактирование в вашей DataGrid, было бы проще всего установить
IsReadOnly="True"
на вашемDataGrid
, чтобы полностью отключить редактирование, и установить этот стиль наTextBox
в вашемDataGridTemplateColumn
. Это избавило бы вас от многих лишних XAML-кодов, таких какIsReadOnly="True"
<DataGrid ItemsSource="{Binding Path=MyTypeCollection}" AutoGenerateColumns="False" IsReadOnly="True"> <!-- This could also go in Window.Resources, UserControl.Resources, etc --> <DataGrid.Resources> <Style x:Key="SalesTextBoxStyle" TargetType="{x:Type TextBox}"> <!-- Set Default --> <Setter Property="IsReadOnly" Value="True" /> <Style.Triggers> <DataTrigger Binding="{Binding Department}" Value="Retail"> <Setter Property="IsReadOnly" Value="False" /> </DataTrigger> </Style.Triggers> </Style> </DataGrid.Resources> <DataGrid.Columns> <DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/> <DataGridTextColumn Header="Department" Binding="{Binding Path=Department}" /> <DataGridTemplateColumn Header="Sales"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBox Text="{Binding Path=Sales}" Style="{StaticResource SalesTextBoxStyle}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
Если вам нужна функция редактирования DataGrid по умолчанию, вы все равно можете использовать то же самое, но вам понадобится только один
TextBox
/TextBlock
в вашемDataTemplate
вместоStackPanel
и нескольких объектов.И если вы действительно хотите, чтобы он отображал фактический
TextBlock
вместоTextBox
, когда пользователь не имеет возможности редактировать, вы можете использоватьContentControl
и переключать его свойствоContentTemplate
сDataTrigger
<DataGrid.Resources> <DataTemplate x:Key="TextBoxTemplate"> <TextBox Text="{Binding Path=.}" /> </DataTemplate> </DataGrid.Resources> ... <DataGridTemplateColumn> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ContentControl x:Name="salesControl" Content="{Binding Sales}" /> <DataTemplate.Triggers> <DataTrigger Binding="{Binding Department}" Value="Retail"> <Setter TargetName="salesControl" Property="ContentTemplate" Value="{StaticResource TextBoxTemplate}" /> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
Вы также можете подписаться на событие
BeginningEdit
DataGrid, а затем добавить простую проверку кода.В XAML:
<DataGrid BeginningEdit="DataGrid_BeginningEdit" />
Пример кода:
private void DataGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e) { RowViewModel VM = (RowViewModel)((DataGrid)sender).SelectedItem; if (!VM.IsRetail) { e.Cancel = true; } }
Я заставил его работать, используя этот код. Я не совсем понимаю его, но он работает так, как я хочу, чтобы он работал. Спасибо, Рейчел!
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Path=Data}"> <DataGrid.Resources> <DataTemplate x:Key="TextBoxTemplate"> <TextBox Text="{Binding Path=Text, StringFormat=c0}" /> </DataTemplate> </DataGrid.Resources> <DataGrid.Columns> <DataGridTextColumn Header="Department" Binding="{Binding Path=Department, Mode=OneTime}" /> <DataGridTextColumn Header="Name" Binding="{Binding Path=Name, Mode=OneTime}" /> <DataGridTemplateColumn Header="Sales"> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <ContentControl x:Name="salesControl" DataContext="{Binding Path=.}"> <TextBlock Text="{Binding Path=Sales, Mode=TwoWay, StringFormat=c0}" /> </ContentControl> <DataTemplate.Triggers> <DataTrigger Binding="{Binding Department}" Value="Retail"> <Setter TargetName="salesControl" Property="ContentTemplate" Value="{StaticResource TextBoxTemplate}" /> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Sales, StringFormat=c0}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>