2

編集可能な DataGridTemplateColumn があります。ビジネス オブジェクトが何らかの基準を満たしている場合にのみ、ユーザーがこの列のセルの内容を編集できるようにしたいと考えています。ビジネス オブジェクトが INotifyPropertyChanged を実装し、NameDepartment、およびSalesの 3 つのプロパティを持っているとします。 NameDepartmentは文字列で、Salesは double です。

Departmentが "Retail"の場合にのみ、ユーザーがSales値を編集できるようにしたいと考えています。これを行うために使用できるデータグリッドは次のとおりです。

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

2 つの Text 要素を持つスタック パネルを使用しています。テキスト要素の可視性でバインディングを使用して、テキスト要素を切り替えます。Departmentの値が "Retail" ではない行がある場合、セルが表示モードか編集モードかに関係なく、 Sales列に TextBlock を表示します。

これは私には不器用な解決策のようです。これらのタイプのセルが編集モードに完全に入らないようにする方法はありますか? 部門が「小売」の場合にのみ編集モードを許可したい。これは可能ですか?

編集:コードを追加します。

@レイチェル。ご協力ありがとうございました。すべてが正しいことを確認するために、すべてのデータグリッド 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と、TextBox が表示されますが、値がありません (こちらを参照)。TextBoxTemplate の TextBox がバインドを指定しているため、値がない理由がわかりません。これがなぜなのか知っていますか?

編集: このソリューションにはもう 1 つの問題があることに気付きました。Sales 列の値を実際に編集することはできません。試してみると、元の編集前の値に戻ります。

4

3 に答える 3

3

Departmentが"Retail"に等しいかどうかに基づいてDataTrigger、プロパティの値を切り替えるaを使用します。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"し、でこのスタイルを設定するのが最も簡単です。これにより、次のような余分なXAMLコードの多くが削除されます。DataGridTextBoxDataGridTemplateColumnIsReadOnly="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/だけです。TextBlockDataTemplateStackPanel

また、ユーザーが編集する機能を持っていないときに、実際にを表示するのTextBlockではなく実際に表示したい場合は、を使用して、プロパティをTextBoxContentControlContentTemplateDataTrigger

<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>
于 2013-03-21T16:48:52.223 に答える
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>
于 2013-03-21T20:36:50.330 に答える
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; }
}
于 2013-03-21T20:01:35.647 に答える