DataGrid:仅在保存第一行的更改后才允许编辑第二行

时间:2014-01-27 11:01:43

标签: wpf vb.net mvvm datagrid

我有一个DataGrid,其ItemsSource绑定到ViewModel类型ObservableCollection(of MY_TYPE)的属性。另外,在ViewModel中我还有一个名为SelectedTarget的属性,它绑定到SelectedItem的{​​{1}}(类型当然是MY_TYPE)。

现在我想要实现的是:用户可以将光标移动到另一行,只要前一行(DataGrid)没有任何更改,否则他必须首先保存这些更改。但我不知道该怎么做。

感谢您的帮助!

更新

这是我的xaml代码和ViewModel属性,就像Sheridan所建议的那样。

xaml

SelectedTarget

ViewModel中的属性:

<DataGrid Grid.Column="1" x:Name="ItemsGrid" ItemsSource="{Binding MyItems}" SelectionMode="Single"  AutoGenerateColumns="False"
                       CanUserResizeRows="False" CanUserSortColumns="True" IsReadOnly="True" VirtualizingStackPanel.IsVirtualizing="True"
                       VirtualizingStackPanel.VirtualizationMode="Standard" EnableRowVirtualization="True" 
                       SelectedItem="{Binding SelectedTarget, Mode=TwoWay}"                        
                       SelectionUnit="FullRow">

我已经检查过,当Public Property SelectedTarget As MY_TYPE Get Return _selectedTarget End Get Set(value As MY_TYPE) If _selectedTarget Is Nothing OrElse (_selectedTarget.Status <> Status.Editing AndAlso _selectedTarget.Status <> Status.New) Then _selectedTarget = value RaisePropertyChanged("SelectedTarget") End If End Set End Property Private _selectedTarget As MY_TYPE Status正在编辑时,它本身不会更改SelectedTarget。但是,这不会阻止另一行中的值进行更改。无论如何,光标会移动到另一行,但我不确定这是否意味着我的SelectedTarget绑定无法正常工作。另一方面,如果我根本没有在SelectedItem中设置SelectedItem的绑定,即使我没有在第一行中保存更改,值仍会在第二行中更改。这是有道理的,因为无论如何每一行都是自然地绑定到一个项目。

2 个答案:

答案 0 :(得分:2)

以下是如何执行此操作的示例。我知道它的丑陋,但你明白了。)

代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new VM();
    }
}

public class VM : INotifyPropertyChanged
{
    private ObservableCollection<MyItem> mySource;

    private MyItem myTarget;

    public ObservableCollection<MyItem> MySource
    {
        get { return mySource; }
        set { mySource = value; }
    }

    public MyItem MyTarget
    {
        get { return myTarget; }
        set
        {
            if (myTarget == null)
                myTarget = value;
            else if (myTarget.IsSaved)
                myTarget = value;

            INotifyPropertyChanged("MyTarget");
        }
    }

    public VM()
    {
        mySource = new ObservableCollection<MyItem>();

        mySource.Add(new MyItem { Text1 = "1", Text2 = "8" });
        mySource.Add(new MyItem { Text1 = "2", Text2 = "7" });
        mySource.Add(new MyItem { Text1 = "3", Text2 = "6" });
        mySource.Add(new MyItem { Text1 = "4", Text2 = "5" });
        mySource.Add(new MyItem { Text1 = "5", Text2 = "4" });
        mySource.Add(new MyItem { Text1 = "6", Text2 = "3" });
        mySource.Add(new MyItem { Text1 = "7", Text2 = "2" });
        mySource.Add(new MyItem { Text1 = "8", Text2 = "1" });
    }

    //INotifyPropertyChanged
}

public class MyItem : INotifyPropertyChanged
{
    private string text1;

    public string Text1
    {
        get { return text1; }
        set
        {
            text1 = value;
            isSaved = false;

            INotifyPropertyChanged("Text1");
            INotifyPropertyChanged("IsSaved");
        }
    }

    private string text2;

    public string Text2
    {
        get { return text2; }
        set
        {
            text2 = value;
            isSaved = true;

            INotifyPropertyChanged("Text2");
            INotifyPropertyChanged("IsSaved");
        }
    }

    private bool isSaved = true;

    public bool IsSaved
    {
        get { return isSaved; }
        set
        {
            isSaved = value;

            RaisePropertyChanged(() => Reg(() => IsSaved));
        }
    }

    //INotifyPropertyChanged
}

XAML

<DataGrid Name="MyDataGrid" ItemsSource="{Binding MySource}"
          SelectedItem="{Binding MyTarget, UpdateSourceTrigger=PropertyChanged}">
    <DataGrid.Resources>
        <Style TargetType="{x:Type DataGridCell}">
            <Setter Property="Visibility" Value="Visible"/>
            <Style.Triggers>

                <!-- for your other items-->
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition  Binding="{Binding ElementName=MyDataGrid, Path=SelectedItem.IsSaved, UpdateSourceTrigger=PropertyChanged}" Value="false"/>
                        <Condition Binding="{Binding IsSaved}" Value="true"/>
                    </MultiDataTrigger.Conditions>
                    <MultiDataTrigger.Setters>
                        <Setter Property="Visibility" Value="Hidden"/>
                    </MultiDataTrigger.Setters>
                </MultiDataTrigger>

            </Style.Triggers>
        </Style>
    </DataGrid.Resources>

</DataGrid>

修改

我找到了一种显示Row的方法,我希望你喜欢它:)

        <Style TargetType="{x:Type DataGridRow}">
            <Style.Triggers>

                <!-- for your other items-->
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition  Binding="{Binding ElementName=MyDataGrid, Path=SelectedItem.IsSaved, UpdateSourceTrigger=PropertyChanged}" Value="false"/>
                        <Condition Binding="{Binding IsSaved}" Value="true"/>
                    </MultiDataTrigger.Conditions>
                    <MultiDataTrigger.Setters>
                        <Setter Property="IsEnabled" Value="False"/>
                    </MultiDataTrigger.Setters>
                </MultiDataTrigger>

            </Style.Triggers>
        </Style>

答案 1 :(得分:1)

第一步是创建一些基本框架,告诉您项目是否有变化。这可以使用MY_TYPE类的另一个实例轻松实现,只需比较每个属性的值即可。

下一阶段是阻止用户更改所选项目,如果他们对当前对象进行了更改。如果您的SelectedTarget属性绑定了正确的数据,那么您应该能够阻止用户更改当前行:

public MY_TYPE SelectedTarget
{
    get { return selectedTarget; }
    set 
    {
        if (!SelectedTarget.HasChanges)
        {
            selectedTarget = value; 
            NotifyPropertyChanged("SelectedTarget"); 
        }
    }
}

最后,当用户保存当前项目时,您需要同步两个对象以表示不再有任何更改,然后用户将能够再次更改记录。