2013-03-21 61 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>