Обновите несколько таблиц данных в WPF для заголовка заголовка - PullRequest
0 голосов
/ 02 ноября 2018

У меня есть форма с динамическим количеством данных, которые вводятся программно каждый на новой вкладке.

Моя проблема в том, что мне нужно изменить заголовок каждого столбца. Я пытался сделать это с помощью метода

DataGridForSupplier.Columns[0].Header = "123";

, но это продолжает сбой с ошибкой:

Индекс был вне диапазона. Должен быть неотрицательным и меньше размера коллекции

Оказывается, проблема в том, что сетка не закончила загрузку. Так что после ожидания загрузки всех вкладок и добавления данных во все сетки, даже тогда код

DataGridForSupplier.Columns[0].Header = "123";

все равно потерпит крах. Если вкладки оставлены для загрузки сами по себе без изменения заголовка, то сетка данных показывает нормально.

Я просто ЛЮБЛЮ, чтобы сделать это в XAML, проблема в том, что, видя, что я не знаю, сколько сеток будет загружаться во время выполнения, я попытался сделать это сзади. Так что на данный момент я открыт для любого решения. Я пытался найти решение, которое включало бы в себя что-то, что могло бы «охватить» все данные. К счастью, все заголовки данных будут повторяться на всех вкладках. Таким образом, заголовок 1 на вкладке 1 - 10 будет таким же. Заголовок 2 на вкладке 1 - 10 будет таким же

Что-то вроде

  <DataGridTemplateColumn.Header> 
    <TextBlock Text="{Binding DataContext.HeaderNameText, RelativeSource=>> RelativeSource AncestorType={x:Type DataGrid}}}" /> 
  </DataGridTemplateColumn.Header> 

но это должно повторяться для каждой Решетки. Это, кажется, ускользает от меня в данный момент. Любая помощь приветствуется.

1 Ответ

0 голосов
/ 12 мая 2019

Довольно длинный ответ, но это решение не требует дополнительных библиотек, сторонних инструментов и т. Д. Вы можете расширить его по своему желанию позже, например, для добавления ловушек для перемещения мышью / над / перетаскиванием / падением / фокусировкой, и т. д. Сначала посылка на подклассы, которую я узнал в начале своего обучения WPF. Вы не можете создать подкласс xaml-файла, но можете это сделать с помощью файла кода .cs. В этом случае я переклассифицировал DataGrid в MyDataGrid. Затем я создал интерфейс для известного типа элемента управления, чтобы обеспечить связь заданных функций / методов / свойств. Я сократил эту версию, чтобы охватить только то, что вам нужно.

Интерфейс, приведенный ниже, просто представляет любой класс, использующий этот интерфейс, ДОЛЖЕН ИМЕТЬ МЕТОД с именем MyDataGridItemsChanged и ожидает параметр MyDataGrid .. достаточно просто

public interface IMyDataGridSource
{
   void MyDataGridItemsChanged(MyDataGrid mdg);
}

Теперь объявляем в коде MyDataGrid, полученный из DataGrid. В этом классе я добавляю частное свойство типа IMyDataGridSource для захвата во время выполнения после построения и привязки данных.

public class MyDataGrid : DataGrid
{
   // place-holder to keep if so needed to expand later
   IMyDataGridSource boundToObject;

   public MyDataGrid()
   {
      // Force this class to trigger itself after the control is completely loaded,
      // bound to whatever control and is ready to go
      Loaded += MyDataGrid_Loaded;
   }

   private void MyDataGrid_Loaded(object sender, RoutedEventArgs e)
   {
      // when the datacontext binding is assigned or updated, see if it is based on 
      // the IMyDataGridSource object.  If so, try to type-cast it and save into the private property
      // in case you want to add other hooks to it directly, such as mouseClick, grid row changed, etc...
      boundToObject = DataContext as IMyDataGridSource;
   }

   // OVERRIDE the DataGrid base class when items changed and the ItemsSource
   // list/binding has been updated with a new set of records    
   protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
   {
      // do whatever default behavior
      base.OnItemsChanged(e);

      // if the list is NOT bound to the data context of the IMyDataGridSource, get out
      if (boundToObject == null)
         return;

      // the bound data context IS of expected type... call method to rebuild column headers
      // since the "boundToObject" is known to be of IMyDataGridSource,
      // we KNOW it has the method... Call it and pass this (MyDataGrid) to it
      boundToObject.MyDataGridItemsChanged(this);
   }
}

Далее в форму, куда вы помещаете сетку данных. Вам нужно будет добавить ссылку «xmlns» в ваш проект, чтобы вы могли добавить «MyDataGrid» вместо «DataGrid». В моем случае мое приложение называется «StackHelp», поскольку здесь я делаю различные тесты из других предложенных ответов. «Xmlns: myApp» просто делает ALIAS «myApp» для дизайнера, чтобы у него был доступ к классам в моем приложении. Затем я могу добавить

<Window x:Class="StackHelp.MyMainWindow"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:myApp="clr-namespace:StackHelp" 
   Title="Main Window" Height="700" Width="900">

   <StackPanel>
      <!-- adding button to the main window to show forced updated list only -->
      <Button Content="Refresh Data" Width="100" 
         HorizontalAlignment="Left" Click="Button_Click" />

      <myApp:MyDataGrid 
         ItemsSource="{Binding ItemsCollection, NotifyOnSourceUpdated=True}"
         AutoGenerateColumns="True" />

   </StackPanel>
</Window>

Теперь, в коде MyMainWindow.cs

namespace StackHelp
{
   public partial class MyMainWindow : Window
   {
      // you would have your own view model that all bindings really go to
      MyViewModel VM;

      public MyMainWindow()
      {
         // Create instance of the view model and set the window binding 
         // to this public object's DataContext
         VM = new MyViewModel();
         DataContext = VM;

         // Now, draw the window and controls
         InitializeComponent();
      }

      // for the form button, just to force a refresh of the data.
      // you would obviously have your own method of querying data and refreshing.
      // I am not obviously doing that, but you have your own way to do it.
      private void Button_Click(object sender, RoutedEventArgs e)
      {
         // call my viewmodel object to refresh the data from whatever
         // data origin .. sql, text, import, whatever
         VM.Button_Refresh();
      }
   }
}

Наконец, к моему образцу ViewModel, который включает IMyDataGridSource

public class MyViewModel : IMyDataGridSource, INotifyPropertyChanged
{
   public event PropertyChangedEventHandler PropertyChanged;
   protected virtual void RaisePropertyChanged(string propertyName)
   { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }

   public ObservableCollection<OneItem> ItemsCollection { get; set; } 
      = new ObservableCollection<OneItem>();


   public void Button_Refresh()
   {
      ItemsCollection = new ObservableCollection<OneItem>
      {
         new OneItem{ DayName = "Sunday", DayOfWeek = 0},
         new OneItem{ DayName = "Monday", DayOfWeek = 1},
         new OneItem{ DayName = "Tuesday", DayOfWeek = 2},
         new OneItem{ DayName = "Wednesday", DayOfWeek = 3},
         new OneItem{ DayName = "Thursday", DayOfWeek = 4},
         new OneItem{ DayName = "Friday", DayOfWeek = 5 },
         new OneItem{ DayName = "Saturday", DayOfWeek = 6 }
      };
      RaisePropertyChanged("ItemsCollection");      
   }


   // THIS is the magic hook exposed that will allow you to rebuild your
   // grid column headers
   public void MyDataGridItemsChanged(MyDataGrid mdg)
   {
      // if null or no column count, get out.
      // column count will get set to zero if no previously set grid
      // OR when the items grid is cleared out. don't crash if no columns
      if (mdg == null)
         return;

      mdg.Columns[0].Header = "123";
   }
}

Теперь, сделаем этот шаг дальше. Я не знаю, как вы управляете вашими моделями представлений, и у вас может быть несколько сеток в ваших формах и тому подобное. Вы можете создать вышеупомянутый класс MyViewModel как меньшее подмножество, такое как класс MyDataGridManager. Таким образом, каждая сетка данных связана со своим собственным экземпляром MyDataGridManager. Он имеет собственный список запросов / заполнения для сетки, обрабатывает собственные заголовки столбцов перестроения, щелчки мыши (если вы хотите расширить), выбранные изменения записи и т. Д.

Надеюсь, это вам поможет. Опять же, для этого не требуются никакие другие сторонние библиотеки, и вы можете расширять их по мере необходимости. Я лично сделал это и многое другое для сетки данных и нескольких других элементов управления для определенной обработки шаблонов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...