首页 > 解决方案 > 当只有显式更改的行应该被更改时,datagrid 中的多行正在更改

问题描述

我有两个数据网格,都使用相同的 xaml(除了一个有额外的列)。一个在主窗口中,另一个在用户控件内。两者都绑定到相同项目的集合(一个当前是 ObservableCollection,另一个是数组)。项目使用 MVVM(或近似值)。

数组/主窗口一个正常工作 - 位置组合框加载到选定的值(它不为空)并且更改该值只会影响它被更改的行。

ObservableCollection/usercontrol 没有。窗口打开时不会加载位置列中的值,直到您向下滚动然后再次向上滚动。更改位置组合框会更改每个可见行(或如果关闭虚拟化,则为每行)中显示的值......包括禁用的组合框。Bonding Level 组合框不会发生同样的情况,它的处理方式基本相同。无论呈现的数据是数组还是 ObservableCollection,都会发生这种情况。

用于生成行的类的每个实例都应该是完全独立的,没有代码隐藏来混淆值,并且在另一个文件中使用集合中完全相同的类型的极其相似的 xaml 和 c# 工作。我搞不清楚了!

截图如下:

正确的行为(主窗口、数组)

https://i.imgur.com/SJIsTOT.png (立即加载,禁用的组合框中没有值)

https://i.imgur.com/cmjaPoR.png (单行更改)

损坏的行为(用户控件嵌入到 tabcontrol、ObservableCollection)

https://i.imgur.com/yC3iAas.png (未在打开的窗口上加载)

https://i.imgur.com/aQgPMCN.png (滚动后加载,包括无效值)

https://i.imgur.com/dqo39aB.png (一个组合框改变,所有行改变)

DataGrid 的 XAML 和行为不端的组合框列(无绑定错误):

<DataGrid Grid.Row ="1" Width="Auto" Height="Auto" AlternatingRowBackground="#FBE9D9" AlternationCount="2"
                AutoGenerateColumns="False" GridLinesVisibility="None"
                ItemsSource="{Binding Familiars}" IsSynchronizedWithCurrentItem="True">
            <DataGrid.InputBindings>
                <MouseBinding MouseAction="LeftDoubleClick" Command="{Binding OpenDataFamiliarWindow}" CommandParameter="{Binding Familiars/}"/>
            </DataGrid.InputBindings>
            <DataGrid.Resources>
                <local_c:OwnedToBoolConverter x:Key="OwnedToBoolConverter"/>
                <local_c:EnemyTypeToColourConverter x:Key="EnemyTypeToColour"/>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
            </DataGrid.Resources>

            <DataGridTemplateColumn Header="Location" Width="Auto" IsReadOnly="False">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ComboBox  ItemsSource="{Binding AvailableLocationTypes}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinWidth="90"
                                               SelectedItem="{Binding Info.Location, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                                               IsSynchronizedWithCurrentItem="True" IsEnabled="{Binding Info.Owned, Converter={StaticResource OwnedToBoolConverter}}">
                            <ComboBox.ItemTemplate>
                                <DataTemplate>
                                    <TextBlock Text="{Binding Converter={StaticResource DescConverter}, Mode=OneTime}"/>
                                </DataTemplate>
                            </ComboBox.ItemTemplate>
                        </ComboBox>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
</DataGrid>

UserControl 旨在绑定到的类(以及与本质上相同的数据网格的工作使用不同的唯一位):

public class ColiseumVenue : INotifyPropertyChanged
    {
        public BitmapImage HeaderImage { get; private set; }
        public string Name { get; private set; }
        public ObservableCollection<FamiliarViewModel> Familiars { get; private set; } = new ObservableCollection<FamiliarViewModel>();
        private IModel m_Model;

        public ColiseumVenue(IModel model, string name, IEnumerable<FamiliarViewModel> familiars)
        {
            Name = name;
            m_Model = model;
            HeaderImage = ImageLoader.LoadImage(Path.Combine(ApplicationPaths.GetViewIconDirectory(), name + ".png"));

            foreach(var familiar in familiars)
            {
                Familiars.Add(familiar);
            }
        }

        public ColiseumView Window { get; set; }
        private BaseCommand m_openDataFamiliarWindow;
        public ICommand OpenDataFamiliarWindow
        {
            <snip>
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

FamiliarViewModel 类的公共变量是:

public class FamiliarViewModel : INotifyPropertyChanged
{
    public FamiliarInfo Info { get; set; }
    public LocationTypes[] AvailableLocationTypes { get; private set; }
    public OwnershipStatus[] AvailableOwnershipStatuses { get; private set; }
    public BondingLevels[] AvailableBondingLevels { get; private set; }
    public BookmarkState[] AvailableBookmarkStates { get; private set; }
}

FamiliarInfo 类中绑定的部分是:

public ICRUD<OwnedFamiliar> OwnedFamiliar
{
    get { return m_OwnedFamiliar; }
    set
    {
        if(m_OwnedFamiliar != value)
        {
            m_OwnedFamiliar = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Owned"));
        }
    }
}

public OwnershipStatus Owned => OwnedFamiliar != null ? OwnershipStatus.Owned : OwnershipStatus.NotOwned;
public BondingLevels? BondLevel
{
    get
    {
        return OwnedFamiliar?.Fetch()?.BondingLevel;
    }
    set
    {
        if (value.HasValue)
        {
            OwnedFamiliar?.Update(f => f.BondingLevel = value.Value);
        }
    }
}
public LocationTypes? Location
{
    get
    {
        return OwnedFamiliar?.Fetch()?.Location;
    }
    set
    {
        if (value.HasValue)
        {
            OwnedFamiliar?.Update(f => f.Location = value.Value);
        }
    }
}

标签: c#wpfmvvmdatagrid

解决方案


结果与以下问题相同:WPF MVVM DataGridComboboxColumn change one row updates all

所选答案(将 IsSynchronizedWithCurrentItem 设置为 null)有效。


推荐阅读