【问题标题】:How to keep my items in datagrid in sequence order when item from middle is deleted WPF C#删除中间项目时如何将我的项目按顺序保存在数据网格中 WPF C#
【发布时间】:2017-02-12 22:10:08
【问题描述】:

我正在以这种方式将项目从数据库加载到我的DataGrid(在表单加载时):

dataGridArticles.ItemsSource = null;
dataGridArticles.ItemsSource = listCurrentArticles;

我可以将项目添加到我的数据网格列表中,并且我可以通过按 DEL 键来删除它们数据网格会自动将其从列表中删除>。

但是当我在作为数据网格源的列表中输入项目时,我也在为每个项目设置 OrdinalNumber,例如,当我将新项目添加到列表中时,我正在做下一件事:

article.OrdinalNumber = GetCurrentlyMaxOrdinalNumber()+1;

所以如果我一个接一个地添加项目,序数将是 1,2,3,4,5... 等等,像这样(标记为红色):

我的存储过程从文章表中返回最大序数:

CREATE DEFINER=`root`@`localhost` PROCEDURE `ArticleGetNextCodeNumber`()
BEGIN
Select ifnull(max(OriginalArticleCode),0)
from articles;
END

当我向列表中添加新项目时,会发生以下情况: 我正在为新文章设置下一个序数和其他一些属性:

 private void btnSaveChangesOnArticle_Click(object sender, RoutedEventArgs e)
        {

            try
            {
                if (newItem)
                {


                    Article newArticle = new Article();

                    newArticle.ArticleCode = txtArticleCode.Text.Trim();
                    newArticle.OriginalArticleCode = Convert.ToInt32(ArticlesController.Instance.GetNextArticleCode()) + 1; // Here I'm setting new article ordinal number

                    newArticle.Title = txtArticleTitle.Text.Trim();
                    newArticle.Price = Convert.ToDecimal(txtPrice.Text.Trim());


                    var lastInserted = ArticlesController.Instance.Save(newArticle);



                    MessageBox.Show("Operation Successful.");



                    listCurrentArticles.Add(lastInserted);

                    dataGridArticles.ItemsSource = null;
                    dataGridArticles.ItemsSource = listCurrentArticles;
                }
            }
        }
    }

我现在想知道,当用户按 DELETE KEY 从我的数据网格中删除某些项目时,我该如何重新组织我的序数,因为如果我向我的数据网格添加 5 个项目,并且如果用户删除第二个项目,我的订单可能看起来像这样:1 3 4 5.. insted of 1 2 3 4

所以我的问题是伙计们,我该如何重新组织它,当某些事情发生变化以使其始终保持顺序时(所以也许我不需要在数据库中保留序数,因为这对我来说并不重要,我使用它只是因为更好的 UI 外观,向用户显示他向 DataGrid 添加了多少项目)。

非常感谢, 干杯!

【问题讨论】:

    标签: c# wpf list datagrid


    【解决方案1】:

    您可以将 OrdinalNumber DataGridTextColumn 替换为 DataGridTemplateColumn 并使用转换器返回父 DataGridRow 容器的 GetIndex() 方法的值。

    您需要同时绑定到父 DataGridRowItems 属性的 Count 属性 DataGrid 本身,以便在项目数量发生变化时刷新绑定,即当一个项目添加或删除。

    这应该很容易实现。您创建一个实现IMultiValueConverter 接口的类:

    namespace WpfApplication3
    {
        public class RowNumberConverter : IMultiValueConverter
        {
            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            {
                return ((values[0] as DataGridRow).GetIndex() + 1).ToString();
            }
    
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    }
    

    并像这样使用它:

    <DataGrid x:Name="dataGridArticles" AutoGenerateColumns="False" xmlns:local="clr-namespace:WpfApplication3">
        <DataGrid.Resources>
            <local:RowNumberConverter x:Key="RowNumberConverter" />
        </DataGrid.Resources>
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="#" IsReadOnly="True">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock>
                            <TextBlock.Text>
                                <MultiBinding Converter="{StaticResource RowNumberConverter}">
                                    <Binding Path="." RelativeSource="{RelativeSource AncestorType=DataGridRow}" />
                                    <Binding Path="Items.Count" RelativeSource="{RelativeSource AncestorType=DataGrid}" />
                                </MultiBinding>
                            </TextBlock.Text>
                        </TextBlock>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <!-- + the rest of your columns -->
        </DataGrid.Columns>
    </DataGrid>
    

    【讨论】:

    • 它工作得很好,但为什么我需要将 xmlns:local="clr-namespace:WpfApplication3" 包含到我的数据网格中,因为我需要从位于其中的代码访问类?是否会弄乱其他任何与我的数据网格的行为有关的东西?并且因为这些项目正在从数据库中填充我的数据网格,我可以以某种方式检测用户何时删除项目,我知道 UI 会处理它看起来像项目被删除,但它仍然在数据库中?所以,伙计,我能否以某种方式捕捉从数据网格中删除项目的事件,以调用我的删除存储过程来完全删除它:)
    • 您需要包含命名空间映射,以便编译器解析转换器类型。不,它不会影响 DataGrid 中的任何其他内容。您只是告诉编译器在哪个命名空间中定义了 RowNumberConverter 类。
    • 我是否应该提出新问题,因为我想在从 UI 数据网格中删除项目时真正从我的数据库中删除项目。 :)
    • 是的。如果您有新问题,您应该提出新问题。
    【解决方案2】:

    查看这个可能解决您问题的相关问题。

    Column/Row index in a DataGrid column

    【讨论】:

      【解决方案3】:

      您最好的选择是删除 OrdinalNumber 属性(因为您不需要它,正如您所说)并使用 DataGrid.RowHeaderTemplate 和转换器。这是一个工作示例:

      主窗口

          public MainWindow()
          {
              InitializeComponent();
              this.DataContext = this;
              listCurrentArticles = new ObservableCollection<Article>() { new Article { Text = "k" }, new Article { Text = "l" } };
          }
          public ObservableCollection<Article> listCurrentArticles { get; set; }
      

      Xaml

      <Window.Resources>
          <local:HeaderConverter x:Key="headerConverter"/>
      </Window.Resources>
      
      <Grid>
          <DataGrid DataContext="{Binding}" ItemsSource="{Binding listCurrentArticles}">
              <DataGrid.RowHeaderTemplate>
                  <DataTemplate>
                      <TextBlock MinWidth="25" TextAlignment="Center">
                          <TextBlock.Text>
                              <MultiBinding Converter="{StaticResource headerConverter}">
                                  <Binding Path="ItemsSource" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGrid}" />
                                  <Binding Path="Item" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridRow}"/>
                              </MultiBinding>
                          </TextBlock.Text>
                      </TextBlock>
                  </DataTemplate>
              </DataGrid.RowHeaderTemplate>
          </DataGrid>
      </Grid>
      

      转换器

      public class HeaderConverter : IMultiValueConverter
      {
          public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
          {
              ObservableCollection<Article> list = values[0] as ObservableCollection<Article>;
              Article obj = values[1] as Article;
              int ind = list.IndexOf(obj);
              if (ind == -1)
                  return "+";
              else
                  return (ind + 1).ToString();
          }
      
          public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
          {
              throw new NotImplementedException();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2018-02-17
        • 1970-01-01
        • 1970-01-01
        • 2012-08-28
        • 2023-03-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多