2013-03-21 64 views
2

我有一个可编辑的DataGridTemplateColumn。如果业务对象满足某些标准,我只希望用户能够编辑此列中单元格的内容。假设我的业务对象实现INotifyPropertyChanged并具有三个属性:名称,部门销售名称是字符串,销售是双。如何防止DataGridTemplateColumn基于某些条件进入编辑模式?

我希望用户只有在部门等于“零售”时才能够编辑销售值。这里有一个数据网格我可能会使用要做到这一点:

<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> 

我使用了一个堆叠面板有两个文本元素。我在文本元素的可见性中使用绑定来切换文本元素。如果我有一个值不是“零售”一排,我显示在销售列的单元格是否显示模式或编辑模式一个TextBlock。

这似乎是一个笨拙的解决方案给我。有什么办法可以阻止这些类型的细胞完全进入编辑模式?我只想在部门为“零售”的情况下允许编辑模式。这可能吗?

编辑:添加代码。

@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> 

我几乎得到了我想要的地方。当我在Retail一行点击一个Sales值,一个TextBox显示,但它并没有在它的值(见here)。我不确定它为什么没有值,因为TextBoxTemplate中的TextBox指定了一个绑定。你知道这是为什么吗?

编辑:我注意到一个其他问题该解决方案,我实际上不能编辑销售列的值。如果我尝试,该值将恢复到原始的预编辑值。

回答

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中任何其他的编辑,这将是最容易对你DataGrid设置IsReadOnly="True"禁用完全编辑,并在DataGridTemplateColumn设置在TextBox这种风格。这将摆脱你很多额外的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> 
+0

我的第三个代码块出现了一些错误。在''行上,'Style'属性上出现''Style''类型'DataGridTemplateColumn'上找不到'的错误。如果我将该行注释掉,则在类型为'DataGridCell'的行上找不到'属性'CellTemplate''行的'行。我错误地复制了你的代码吗? – user2023861 2013-03-21 17:48:57

+1

@ user2023861对不起,我写了没有编译器来仔细检查语法。看到我的更新的答案为一个有效的代码示例 – Rachel 2013-03-21 18:10:05

+0

谢谢你看这个。我几乎有我想要的。我有一个小问题:编辑模式期间出现的TextBox最初没有使用“Sales”值加载。我想发布我的所有datagrid xaml代码,所以我对我原来的帖子进行了编辑。我的绑定有问题吗?我如何让TextBox显示'Sales'值? – user2023861 2013-03-21 19:16:47

1

您也可以订阅DataGrid的BeginningEdit事件,然后在代码隐藏中添加一个简单的检查。

在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; } 
} 
1

我得到了它的使用此代码工作。我不完全理解它,但它可以工作,因为我希望它能够工作。谢谢瑞秋!

<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>