使用Comboboxcolumns交换DataGrid中的项目?

问题描述 投票:1回答:1

是)我有的

我有一个UserControl设置在MVC模式与DataGridList模型。我的List比我的DataGrid可以显示更多的项目,这就是为什么我正在寻找一种方法来建立一种方式让我的用户自己选择他们想要的项目。

我需要的

我的DataGrid应该能够执行以下所有操作:

  • 显示我的列表中最多30个项目中的8个
  • 轻松允许用户更改每行的项目
  • 当用户更改我的DataGrid中的单元格值时更新主列表中的模型(如果我使用仅包含8个项目的辅助列表)

理想情况应该是什么样的

当我试图为Pen&Paper游戏DSA(黑眼圈)构建一个自定义字符表生成器时,我很乐意让DataGrid尽可能地与它们的网格相同。

在这里你可以看到一个网格来选择武器技能。第一列包含一个组合框,其中包含所有武器技能的名称。从此框中选择技能时,该行将更改为此技能的统计数据

DSAPIC

我之前只使用过DevExpress GridControls,所以即使没有实现这个功能,我也很难进入“默认”DataGrids。

附加信息:

  • 我从/到xml文件加载并保存我的字符集
  • 字符表应该打印出来

我怎样才能以我想象的方式让它工作/你有其他/更容易解决我的问题的方法吗?

c# wpf datagrid
1个回答
1
投票

两个兴趣点:

  1. 如果希望更新对所有集合都可见,最简单的方法是确保所有集合使用相同的引用来填充自己。
  2. 在相关的说明中,不止一次显示相同的记录将需要特别小心。更新可能看起来很奇怪,因为它们涉及多行。 LINQ查询可能会返回另一个实例。但是,在这种情况下,我们只对显示唯一记录感兴趣,并可选择替换它们。

途径

将属性IsShown添加到行的viewmodel中,以跟踪记录当前是否在datagrid中可见。我们可以使用RowStyle强制执行此操作。

使用CollectionView作为基于datagrid的ItemsSource的组合框。如果未显示记录,则应从组合框中选择。将过滤器添加到集合视图应该可以解决问题。

代码示例

WeaponViewModel.cs

public class WeaponViewModel : ViewModelBase
{
    private readonly string _name;
    private string abbreviation;
    private int damage;
    private bool isShown;

    public WeaponViewModel(string name, string abbreviation, int damage, bool isShown)
    {
        _name = name;
        this.Abbreviation = abbreviation;
        this.Damage = damage;
        this.IsShown = isShown;
    }

    public string Name => _name;

    public string Abbreviation
    {
        get { return abbreviation; }
        set
        {
            abbreviation = value;
            OnPropertyChanged();
        }
    }

    public int Damage
    {
        get { return damage; }
        set
        {
            damage = value;
            OnPropertyChanged();
        }
    }

    public bool IsShown
    {
        get { return isShown; }
        set
        {
            isShown = value;
            OnPropertyChanged();
        }
    }
}

MainViewModel.cs

public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        Weapons = new ObservableCollection<WeaponViewModel>(GetWeapons());
        DropDownWeapons = (CollectionView)new CollectionViewSource { Source = Weapons }.View;
        DropDownWeapons.Filter = DropDownFilter;
    }

    #region DataGrid

    public ObservableCollection<WeaponViewModel> Weapons { get; }

    private WeaponViewModel currentWeapon;
    public WeaponViewModel CurrentWeapon
    {
        get { return currentWeapon; }
        set
        {
            currentWeapon = value;
            OnPropertyChanged();
        }
    }

    #endregion DataGrid

    #region ComboBox

    public CollectionView DropDownWeapons { get; } 

    private WeaponViewModel selectedWeapon;
    public WeaponViewModel SelectedWeapon
    {
        get { return selectedWeapon; }
        set
        {
            if (value != null)
            {
                selectedWeapon = value;
                ReplaceCurrentWith(selectedWeapon);
                OnPropertyChanged();
            }
        }
    }

    private void ReplaceCurrentWith(WeaponViewModel requestedWeapon)
    {
        currentWeapon.IsShown = false;
        requestedWeapon.IsShown = true;
        var currentWeaponIndex = Weapons.IndexOf(currentWeapon);
        var requestedWeaponIndex = Weapons.IndexOf(requestedWeapon);
        Weapons.Move(requestedWeaponIndex, currentWeaponIndex);
        DropDownWeapons.Refresh();
    }

    private bool DropDownFilter(object item)
    {
        var weapon = (WeaponViewModel)item;
        return weapon.IsShown == false;
    }

    #endregion ComboBox

    private static IList<WeaponViewModel> GetWeapons()
    {
        var weapons = new List<WeaponViewModel>
        {
            new WeaponViewModel("Assault Rifle", "AR", 30, true),
            new WeaponViewModel("Submachine Gun", "SM", 17, true),
            new WeaponViewModel("Revolver", "RV", 54, true),
            new WeaponViewModel("Shotgun", "AR", 30, true),
            new WeaponViewModel("Sniper", "SN", 63, true),
            new WeaponViewModel("Rocket Launcher", "RL", 300, true),
            new WeaponViewModel("Grenade Launcher", "GL", 200, true),
            new WeaponViewModel("Minigun", "MG", 20, true),
            new WeaponViewModel("Knife", "KN", 10, false),
            new WeaponViewModel("Baseball Bat", "BB", 6, false),
        };
        return weapons;
    }
}

MainWindow.xaml

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:vm="clr-namespace:WpfApp.ViewModels"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" WindowStartupLocation="CenterScreen">
    <Window.DataContext>
        <vm:MainViewModel/>
    </Window.DataContext>
    <DataGrid ItemsSource="{Binding Weapons}" SelectedItem="{Binding CurrentWeapon}"
              AutoGenerateColumns="False">
        <DataGrid.RowStyle>
            <Style TargetType="{x:Type DataGridRow}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsShown}" Value="False">
                        <Setter Property="Visibility" Value="Collapsed"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </DataGrid.RowStyle>
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="Weapons">
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <ComboBox DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                            ItemsSource="{Binding DropDownWeapons}"
                            SelectedItem="{Binding SelectedWeapon}"
                            DisplayMemberPath="Name"
                            IsEditable="False" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Name}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}" IsReadOnly="True" />
            <DataGridTextColumn Header="AB" Binding="{Binding Abbreviation}" />
            <DataGridTextColumn Header="Damage"  Binding="{Binding Damage}" />
        </DataGrid.Columns>
    </DataGrid>
</Window>
© www.soinside.com 2019 - 2024. All rights reserved.