Довольно длинный ответ, но это решение не требует дополнительных библиотек, сторонних инструментов и т. Д. Вы можете расширить его по своему желанию позже, например, для добавления ловушек для перемещения мышью / над / перетаскиванием / падением / фокусировкой, и т. д. Сначала посылка на подклассы, которую я узнал в начале своего обучения 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. Он имеет собственный список запросов / заполнения для сетки, обрабатывает собственные заголовки столбцов перестроения, щелчки мыши (если вы хотите расширить), выбранные изменения записи и т. Д.
Надеюсь, это вам поможет. Опять же, для этого не требуются никакие другие сторонние библиотеки, и вы можете расширять их по мере необходимости. Я лично сделал это и многое другое для сетки данных и нескольких других элементов управления для определенной обработки шаблонов.