Danke für den Tipp, werde ich mir mal ansehen 😃
Hallo,
Ich habe eine Lösung gefunden.
Ich befinde mich im Event „LoadingRow“ des DataGrids.
Das Binding wird neu gesetzt, aber da die Row gerade beim "Laden" ist, sehe ich keine Änderungen im Text.
Nachdem ich das Binding gesetzt habe, rufe ich nun eine Methode mit „BeginInvoke DispatcherPriority.Loaded“ auf, die das Highlighting durchführen soll.
In dieser Methode ist die Row dann geladen und die Textblöcke beinhalten die richtigen Texte.
Hallo Alf,
tatsächlich klappt es, wenn ich im XAML den BindingMode TwoWay verwende.
Es scheint, als würde bei TwoWay die Bindinginformation nicht verloren gehen, bei OneWay aber schon.
Aber ich suche auch eine Lösung dafür, wenn OneWay verwendet wird, dass es durch das neue Setzen des Bindings den Text nicht verwirft sondern entsprechend dem Binding, den Text aktualisert.
Lieben Gruß
Hallo ihr Lieben,
ich habe ein kleines Testprojekt geschrieben um mein Problem einfach zu veranschaulichen.
Folgender Ablauf:
Ich hoffe ihr könnt mir helfen, wie ich es schaffen kann, dass der Text nach dem Setzen des Bindings vorhanden ist.
XAML
<StackPanelTag="{Binding Path=MissionName, Converter={StaticResource DebugConverter}}">
<TextBlock
Text="{Binding Path=Tag, RelativeSource={RelativeSource AncestorType=StackPanel}" />
</StackPanel>
Code Behind
// Daten für Binding merken
var exp = txtBlock.GetBindingExpression(TextBlock.TextProperty);
txtBlock.Tag = new Tuple<RelativeSource, PropertyPath>(exp.ParentBinding.RelativeSource, exp.ParentBinding.Path)
var inlines = new List<Inline>();
inlines.Add(new Run(text.Substring(0, 1)));
inlines.Add(new Run(text.Substring(1, 2))
{
Background = filterData.SelectionColor,
Foreground = filterData.ForegroundColor
});
inlines.Add(new Run(text.Substring(3, 1)));
txtBlock.Inlines.Clear();
txtBlock.Inlines.AddRange(inlines);
Im Event
var tagData = (Tuple<RelativeSource, PropertyPath>) txtBlock.Tag;
var binding = new Binding { RelativeSource = tagData.Item1, Path = tagData.Item2};
txtBlock.SetBinding(TextBlock.TextProperty, binding); // <- txtBlock.Text ist jetzt ""
// Dieser Aufruf sagt jetzt, IsDirty="true" & Status="Unattached"
var exp = txtBlock.GetBindingExpression(TextBlock.TextProperty);
Ich hoffe ihr habe eine Idee.
Ich weiß, es entspricht nicht MVVM, aber aktuell versuche ich das so um Laufen zu bringen, muss ja irgendwie gehen 😃
Vielen Dank euch allen
Lieben Gruß
Hallo ihr Lieben,
ich habe eine Lösung gefunden. Ist etwas unschön, aber in meinem Fall die einzige die ich gefunden habe.
Die Virtualisierung nutzt beim Scrollen die alten Listelenemte und fügt sie unten wieder an.
Der DataContext hat sich entsprechend dem neuen Listelement aktualisiert, aber die Texte im TextBlock nicht, diese werden aber für das Highlighting verwendet.
Die Lösung war in meinem Fall, dass ich mit im Tag-Property des TextBlocks gewisse BindingExpressions merke und sobald beim Scrollen die nächste Row geladen ist (Event LoadingRow im DataGrid), ich die BindingExpressions entsprechend dem aktualisierten DataContext neu setze.
Das funktioniert aber nur , wenn die GUI bereits gerendert ist. Wird der Code zu früh ausgeführt, sind die BindingExpressions null.
Deshalb ist es wichtig, dass LoadingRow erst nach dem Rendern und nach der eigentlichen Highlighting-Aktion ausgeführt wird.
Wichtigste Änderungen im Überblick
Formular9.xaml
<local:MyGrid
...
local:Highlighter9.RaiseHighlight="{Binding IsFilterReady, Mode=OneWay}"
EnableRowVirtualization="True"
VirtualizingStackPanel.VirtualizationMode="Recycling"/>
Formular9.xaml.cs
public string Filter
{
get => this.filter;
set
{
this.filter = value;
this.RaisePropertyChanged();
this.DisplayedItems.Refresh();
this.IsFilterReady = true;
}
}
public bool IsFilterReady
{
get => this.isFilterReady;
set
{
this.isFilterReady = value;
this.RaisePropertyChanged();
}
}
MyGrid.cs
public class MyGrid : DataGrid
{
public MyGrid()
{
this.LoadingRow += GridOnLoadingRow;
}
public bool IsHighlightingReady { get; set; }
public bool IsVirtualization => VirtualizingPanel.GetIsVirtualizing(this) || this.EnableColumnVirtualization || this.EnableRowVirtualization;
public VirtualizationMode VirtualizationMode => VirtualizingPanel.GetVirtualizationMode(this);
public string Filter { get; set; }
private void GridOnLoadingRow(object sender, DataGridRowEventArgs e)
{
Highlighter9.GridOnLoadingRow((MyGrid)sender, e);
}
}
Highlighter9.cs
public static class Highlighter9
{
// Feuert den Start des Highlighting Prozesses
public static readonly DependencyProperty RaiseHighlightProperty = DependencyProperty.RegisterAttached(
...
new PropertyMetadata(false, null, CoerceValueCallback));
...
private static object CoerceValueCallback(DependencyObject d, object baseValue)
{
// Es ist wichtig zu warten, bis die Liste gefildert wurde, bevor das Highlighting durchgeführt wird.
// Wenn die Listenelemente nicht vollständig gerendert sind fehlen Informationen, die nötig sind wie z.B. BindingExpression.
if ((bool)baseValue)
{
...
var grid = (MyGrid)d;
grid.IsHighlightingReady = false;
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() =>
{
DoAction(grid, filter);
}));
}
return baseValue;
}
...
private static void DoAction(MyGrid grid, string filter)
{
// Aktuelle Daten im Grid speichern, damit Grid nach verzögertem Aufruf die richtigen Daten verwendet.
// Bei mehreren Grids im Formular kommt es sonst zu Komplikationen, dass die Grids die Daten des anderen anziehen, da der Behavior statisch ist.
// Zudem benötigt Grid die Daten damit im Event LoadingRow die richtigen Daten bekannt sind
grid.Filter = filter;
var gridRows = grid.GetDescendants<DataGridRow>().ToList();
foreach (var row in gridRows)
{
HighlightRow(row, grid);
}
grid.IsHighlightingReady = true;
}
...
private static void HighlightTextBlock(TextBlock txtBlock, MyGrid grid)
{
// Prüfen, ob Virtualisierung aktiviert ist
if (grid.IsVirtualization && grid.VirtualizationMode == VirtualizationMode.Recycling)
{
// Property Name aus Binding ermitteln & merken
var exp = txtBlock.GetBindingExpression(TextBlock.TextProperty);
txtBlock.Tag = exp?.ResolvedSourcePropertyName;
}
...
}
public static void GridOnLoadingRow(MyGrid grid, DataGridRowEventArgs e)
{
// Bei erneuter Filtereingabe wird das Event LoadingRow durchgeführt, bevor die eigentliche Verarbeitung des Highlighters durchgeführt wird.
// Die Ausführung des Codes so lange ignorieren, bis der Highlighter seine Verarbeitung abgeschlossen hat.
// Führt sonst zum Fehler, dass BindingExpression Informationen nicht vorhanden sind
if (!grid.IsHighlightingReady)
{
return;
}
// Bei Deaktivierter Virtualisierung Methode verlassen
if (!grid.IsVirtualization)
{
return;
}
if (grid.VirtualizationMode == VirtualizationMode.Recycling)
{
// Textblöcke der Row ermitteln
if (e.Row.GetDescendants<TextBlock>().Any())
{
HighlightRowWithUpdateBinding(e.Row, grid);
}
else
{
// Werden keine Textblöcke gefunden, ist Row zwar geladen, aber noch nicht gerendert. Aufruf verzögern.
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
if (e.Row.GetDescendants<TextBlock>().Any())
{
HighlightRowWithUpdateBinding(e.Row, grid);
}
}), DispatcherPriority.Send);
}
}
else
{
// Hier ist die Row noch nicht gerendert, GetDescendants in HighlightRow findet keine Textboxen, Aufruf verzögern
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
HighlightRow(e.Row, grid);
}), DispatcherPriority.Send);
}
}
private static void HighlightRowWithUpdateBinding(DataGridRow row, MyGrid grid)
{
// Bindings für die TextBlöcke neu setzen
foreach (var txtBlock in row.GetDescendants<TextBlock>())
{
// Property Name aus Binding oder Tag-Property ermitteln
var exp = txtBlock.GetBindingExpression(TextBlock.TextProperty);
var path = exp != null ? exp.ResolvedSourcePropertyName : txtBlock.Tag.ToString();
// Binding neu setzen
var binding = new Binding { Source = txtBlock.DataContext, Path = new PropertyPath(path) };
txtBlock.SetBinding(TextBlock.TextProperty, binding);
}
HighlightRow(row, grid);
}
MyListItem.cs
Ich habe gerade gesehen, dass in der Methode HighlightTextBlock(TextBlock)
direkt beim Einstieg txtBlock.GetBindingExpression(TextBlock.TextProperty)
die entsprechenden Daten liefert, aber am Ende der Methode, nachdem die Inlines
gesetzt wurden, liefert txtBlock.GetBindingExpression(TextBlock.TextProperty)
null.
Da scheint wohl doch das Binding
kaputt zu gehen.
Guten Morgen,
genau das ist leider das Problem, HighlightRow(e.Row
) verwendet die Texte der Textblöcke
um die Inlines
zu aktualisieren, aber die Texte sind in GridOnLoadingRow
noch nicht aktualisiert, im DataContext
sind zwar die neuen Texte, aber in den Textblöcken
im Text noch nicht.
Und ich habe im Grunde versucht irgendetwas zu machen, damit die Aktualisierung der TextBlock
-Texte anhand dem DataContext
neu angestoßen wird.
Vielen Dank für deine schnelle Antwort.
Die Testklasse beinhaltet nur einen gewissen Ausschnitt aus dem Hauptcode um den Fehler zu zeigen, die eigentliche Highlighter
Klasse kann mit den unterschiedlichsten Controls
(z.B. DataGrid
, TreeView
, Alleinstehender TextBlock
, ... ) umgehen. Egal welches Control
, es werden die TextBlöcke
an unterster Ebene ermittelt und der Text entsprechend markiert.
Ich glaube mein Verständnis ist für diese Thematik zu gering, ich hab mir die Links angeschaut aber verstehe nicht, wie ich das für mich nutzen kann.
Wie kann ich sowas so generisch bauen, dass es unabhängig vom ViewModel
funktioniert? Ich bring in meinen Gedanken nichts zusammen. Ich müsste dort dann für jeden sichtbaren TextBlock
Inlines
generieren und dafür sorgen, dass das beim Scrollen auch entsprechend synchronisiert wird.
Zudem muss ich das DataGrid
nutzen, da wir abgeleitete Klassen davon verwenden und die Virtualisierung durch EnableRowVirtualization zwingend erforderlich ist, da die Elemente beim Scrollen entsprechend abgebaut werden.
Hast du evt. noch eine Idee, die mit DataGrid
funktionieren könnte? Evtl. eine eigene Klasse
davon ableiten und darin irgendwas magisches machen, wodurch das funktionieren könnte?
Danke für die Erklärung, dann habe ich mir das wohl falsch abgeschaut.
Also mit EnableRowVirtualization="false" gehts, aber mit true nicht.
Das ist nur eine Testklasse, normalerweise ist mein Code entsprechend ausgelagert.
Die Highlighter Funktionalität soll unabhängig von jeglichen ViewModels verwendet werden können, egal ob DataGrid oder TreeViewCtrl (Eigenes TreeViewControl), egal welche Daten reingeschoben werden. Der Highlighter soll stumpf erkennen, dass dort irgendwo Texte stehen und diese entsprechend markieren.
Oder habe ich das falsch verstanden? Ich habe das jetzt so verstanden, dass ich die ganze Highlighting Geschichte für jedes ViewModel separat machen muss, dass würde aber leider nicht meiner Anforderung von "Überall verwendbar" entsprechen.
Hallo Th69,
danke für den Tipp!
Folgendes geht:
Folgendes geht nicht:
Leider ist die Virtualisierung zwingend nötig denn die Liste kann im Grunde n Einträge besitzen, aktuell ist die Einschätzung bis zu 5000.
Hallo ihr Lieben,
ich stehe vor einem Problem und komme nicht mehr weiter.
Ich habe die Hoffnung, dass ihr mir helfen könnt.
Kurze Erklärung:
Ich habe ein DataGrid (VirtualizingPanel.IsVirtualizing="true") & eine Suchleiste. Gebe ich in der Suchleiste etwas ein wird die Liste entsprechend gefiltert & über ein AttachedProperty der entsprechende Text markiert. Das markieren erfolgt, indem der Text aus einem TextBlock in mehrere Inlines zerlegt wird. In den Inlines, die den Suchtext beinhalten ist dann eine entsprechende Background-Farbe gesetzt.
--> Funktioniert wunderbar
Siehe Bild 1
Problem:
Sobald ich runter und wieder rauf scrolle, enthalten die Elemente, die den sichtbaren Bereich verlassen haben, plötzlich den gleichen Text wie das 2. Element. Gleiches passiert auch am Ende der Liste. Das komische ist, wenn ich erneut runter und wieder rauf scrolle ist der Text teilweise wieder richtig.
Siehe Bild 2
Ich habe mich am Grid auf das Event LoadingRow gehangen und gesehen, dass die Row, die dann in den sichtbaren Bereich kommt, zwar im DataContext die richtigen Daten enthält, aber die Texte in den TextBlöcken sich nicht aktualisiert haben.
Mein Gedanke war, dass evtl. durch das Manipulieren der Inlines das Binding kaputt gegangen ist, aber das scheint nicht der Fall zu sein.
Siehe Bild 3
Ich hoffe ihr könnt mir helfen, nachfolgend der Code zu meinem Testprojekt.
Formular.xaml
<DataGrid
local:Highlighter.Filter="{Binding Filter, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
AutoGenerateColumns="true"
ColumnWidth="100"
ItemsSource="{Binding Path=DisplayedItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
RowHeight="30"
SelectionMode="Single" />
<WrapPanel>
<Label Content="Filter: " />
<TextBox Width="100" Text="{Binding Path=Filter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</WrapPanel>
Formular.xaml.cs
public partial class Formular : INotifyPropertyChanged
{
public ICollectionView DisplayedItems { get; set; }
private string filter;
public string Filter
{
get => this.filter;
set
{
this.filter = value;
this.DisplayedItems.Refresh();
this.RaisePropertyChanged();
}
}
public Formular()
{
InitializeComponent();
this.DataContext = this;
var listItems = new ObservableCollection<MyListItem>()
{
new MyListItem("Alpha", "Mission1"),
new MyListItem("Beta1", "Mission1"),
new MyListItem("Beta1", "Mission2"),
new MyListItem("Beta1", "Mission3"),
new MyListItem("Beta1", "Mission4"),
new MyListItem("Beta1", "Mission5"),
new MyListItem("Beta1", "Mission6"),
new MyListItem("Beta1", "Mission7"),
new MyListItem("Beta1", "Mission8"),
new MyListItem("Beta1", "Mission9"),
new MyListItem("Beta2", "Mission2"),
};
this.DisplayedItems = CollectionViewSource.GetDefaultView(listItems);
this.DisplayedItems.Filter = this.FilterCallback;
}
public bool FilterCallback(object obj)
{
var item = (MyListItem) obj;
return string.IsNullOrEmpty(this.Filter)
|| item.Name.ToUpper().Contains(Filter.ToUpper())
|| item.MissionName.ToUpper().Contains(Filter.ToUpper());
}
}
Highlighter.cs
public static class Highlighter
{
private static string filter;
static Highlighter(){}
#region Filter
public static readonly DependencyProperty FilterProperty =
DependencyProperty.RegisterAttached("Filter", typeof(string), typeof(Highlighter), new PropertyMetadata("", PropertyChangedCallback));
public static void SetFilter(DependencyObject obj, string value)
{
obj.SetValue(FilterProperty, value);
}
public static string GetFilter(DependencyObject obj)
{
return (string)obj?.GetValue(FilterProperty);
}
private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() => DoAction(d)));
}
#endregion
private static void DoAction(DependencyObject d)
{
filter = GetFilter(d);
if (filter == null)
{
return;
}
var grid = (DataGrid)d;
grid.LoadingRow += GridOnLoadingRow;
// Get DataGridRows
var gridRows = grid.GetDescendants<DataGridRow>().ToList();
foreach (var row in gridRows)
{
HighlightRow(row);
}
}
private static void HighlightRow(DataGridRow row)
{
// Get TextBlocks
var txtBlocks = row.GetDescendants<TextBlock>().ToList();
if (!txtBlocks.Any())
{
return;
}
foreach (var txtBlock in txtBlocks)
{
HighlightTextBlock(txtBlock);
}
}
private static void HighlightTextBlock(TextBlock txtBlock)
{
var text = txtBlock.Text;
if (string.IsNullOrEmpty(text))
{
return;
}
// Check whether the text contains the filter text
var index = text.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase);
if (index < 0)
{
// Filter text not found
return;
}
// Generate Inlines with highlighting information
var inlines = new List<Inline>();
while (true)
{
// Text from beginning to filter text
inlines.Add(new Run(text.Substring(0, index)));
// Text that corresponds to the filter text
inlines.Add(new Run(text.Substring(index, filter.Length))
{
Background = Brushes.Yellow
});
// Text from filter text to ending
text = text.Substring(index + filter.Length);
// Check whether the remaining text also contains the filter text
index = text.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase);
if (index < 0)
{
// If not, add remaining text and exit loop
inlines.Add(new Run(text));
break;
}
}
// Replace Inlines
txtBlock.Inlines.Clear();
txtBlock.Inlines.AddRange(inlines);
}
}
MyListItem.cs
public class MyListItem : INotifyPropertyChanged
{
public string name;
public string Name
{
get => name;
set
{
this.name = value;
this.RaisePropertyChanged();
}
}
public string missionName;
public string MissionName
{
get => missionName;
set
{
this.missionName = value;
this.RaisePropertyChanged();
}
}
public MyListItem(string name, string missionName)
{
this.Name = name;
this.MissionName = missionName;
}
}
TH69, du bist mein Held!
Es hat funktioniert!
Vielen vielen Dank 😉
Hallo,
das Problem ist, dass es im Projekt eine Klasse (ExtraDataGridExtend
) gibt, die DataGrid
erweitert und in ihrer ResourceDictionary.xaml denTyrgetType
von DataGridColumnHeader
setzt.
<Style BasedOn="{StaticResource HeaderExtraDataGridExtendStyle}" TargetType="{x:Type DataGridColumnHeader}" />
Nun habe ich aber eine weitere Klasse, die DataGrid erweitert (oder idealerweise ExtraDataGridExtend). Diese soll eigenständig sein, mit einer eigenen ResourceDictionary.xaml.
Nun gibt es aber auch dort einen komplett anderen Style für den DataGridColumnHeader
.
Also auch wieder
<Style BasedOn="{StaticResource HeaderExtraDataGridExtendRotateStyle}" TargetType="{x:Type DataGridColumnHeader}" />
Da beide diese ResourceDictionary.xaml in einm gemeinsamen MergedDictionaries
zusammengeführt werden, gewinnt der letzte Style, der dem DataGridColumnHeader
zugewiesen wurde.
Ich suche nun eine Lösung, wie ich dieses Problem umgehen kann.
Meine Idee wäre gewesen eine eigene DataGridColumnHeader
Klasse zu erstellen. Dann hätte ich eine unabhängige Header-Klasse der ich meinen neuen Style zuweisen könnte ohne den Style für den originalen DataGridColumnHeader zu überschreiben.
Leider ist das nicht möglich, da der DataGridColumnHeadersPresenter
den Typ DataGridColumnHeader
erwartet und ich mein eigene Headerklasse nicht verwenden kann.
Sprich ich suche immer noch eine andere Lösung für das Problem.
Hallo ihr Lieben,
ich stehe vor einem Problem und finde einfach keine Lösung dafür.
Meine Kollegen konnten mir auch nicht weiterhelfen.
Es gibt im Projekt eine XAML, in der alle Ressourcen der selbst erstellten GUI-Elemente eingetragen werden.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<ResourceDictionary.MergedDictionaries>
...
<ResourceDictionary Source="pack://application:,,,/Test.Gui;Component/Fields/ExtraDataGridExtendResources.xaml" />
<ResourceDictionary Source="pack://application:,,,/Test.Gui;Component/Fields/ExtraDataGridExtendRotateResources.xaml" />
...
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Beide oben genannten Elemente leiten von DataGrid ab.
Der Style wird im static Konstruktor entsprechend geladen.
/// <summary>
/// Statischer Konstruktor zum Laden des StandardStyles
/// </summary>
static ExtraDataGridExtendRotate()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ExtraDataGridExtendRotate), new FrameworkPropertyMetadata(typeof(ExtraDataGridExtendRotate)));
}
In den Resources.xaml sind dann alle Styles definiert, ich habe bei den beiden oben genannten jedem Style einen eindeutigen x:Key gegeben, damit sich diese laut meinem Kollegen nicht gegenseitig aufgeben.
Am Ende der Resources.xaml stehen die folgenden Einträge:
<Style BasedOn="{StaticResource BaseExtraDataGridExtendRotateStyle}" TargetType="{x:Type localTest:ExtraDataGridExtendRotate}" />
<Style BasedOn="{StaticResource HeaderExtraDataGridExtendRotateStyle}" TargetType="{x:Type DataGridColumnHeader}" />
Die 2. Zeile weist dem DataGridColumnHeader den entsprechenden Style zu. Da dies in beiden Resources.xaml gemacht wird, könnte dies das Problem sein, warum der Header in ExtraDataGridExtend nun genau so aussieht wie in ExtraDataGridExtendRotate.
Zum Test habe ich eine eigene Header Klasse erstellt und von DataGridColumnHeader abgeleitet.
public class MyDataGridColumnHeader : DataGridColumnHeader
{
static MyDataGridColumnHeader()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyDataGridColumnHeader), new FrameworkPropertyMetadata(typeof(MyDataGridColumnHeader)));
}
}
In einem der beiden oben genannten Resources.xaml habe ich nun am Ende bei dem entsprechenden Eintrag meine Klasse angegeben, damit ich 2 verschiedene Header-Klassen habe und jedem ein entsprechender Style zugewiesen werden kann.
<Style BasedOn="{StaticResource BaseExtraDataGridExtendStyle}" TargetType="{x:Type localTest:ExtraDataGridExtend}" />
<Style BasedOn="{StaticResource HeaderExtraDataGridExtendStyle}" TargetType="{x:Type DataGridColumnHeader}" />
<Style BasedOn="{StaticResource BaseExtraDataGridExtendRotateStyle}" TargetType="{x:Type localTest:ExtraDataGridExtendRotate}" />
<Style BasedOn="{StaticResource HeaderExtraDataGridExtendRotateStyle}" TargetType="{x:Type localTest:MyDataGridColumnHeader}" />
Im 2. Resources.xaml habe ich überall (Styles & Templates) **DataGridColumnHeader **durch **MyDataGridColumnHeader **ersetzt.
An einer Stelle (PART_FillerColumnHeader) habe ich gesehen, dass es funktioniert hat.
<Style x:Key="TestHeader" TargetType="{x:Type DataGridColumnHeadersPresenter}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeadersPresenter}">
<Grid
x:Name="PART_DataGridColumnHeadersPresenter"
HorizontalAlignment="Stretch"
Background="BlueViolet">
<localTest:MyDataGridColumnHeader
x:Name="PART_FillerColumnHeader"
Background="Aqua"
Visibility="Visible" />
<ItemsPresenter x:Name="PART_Items" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Das Problem das aber weiterhin besteht ist der ItemsPresenter.
Ich habe im oben genannten Code-Stück keine Möglichkeit dem ItemsPresenter zu sagen, welchen Typ seine Items haben sollen.
In "Snoop" (siehe Bild) sehe ich, dass dort immer noch der falsche DataGridColumnHeader verwendet wird.
Ich hoffe ihr könnt mir bei meinem Problem weiterhelfen.
Vielen Dank schonmal für eure Mühe.
Liebe Grüße
Anna
Hallo Bernd,
vielen dank für die Antwort.
Schade, dass etwas so "einfaches" nicht mit den vorhandenen Möglichkeiten machbar ist.
Dann versuche ich dass mal.
Grüße Anna
Auch das hat leider nichts gebracht.
Auf dem Bild ist ein Beispiel zu sehen, was ich versuche.
Wenn ich die Headertexte vergrößere und dann wieder verkleinere, werden die Roten Elemente verkleinert und es erscheint ein gelber Bereich, der dort nicht sein sollte.
Meine Erwartung wäre, dass die komplette Spalte wieder kleiner wird.
Die Spalte behält aber die Breite.
Ich habe folgenden Testcode:
<Style
x:Key="ColumnHeaderStyleT11"
BasedOn="{StaticResource {x:Type DataGridColumnHeader}}"
TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Background" Value="Pink" />
<Setter Property="FontSize" Value="{Binding ElementName=Text1, Path=Value, UpdateSourceTrigger=PropertyChanged}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
</Style>
...
<TextBox
Grid.Row="0"
Grid.Column="2"
Grid.ColumnSpan="2"
Text="{Binding ElementName=Text1, Path=Value, UpdateSourceTrigger=PropertyChanged}" />
<Slider
Name="Text1"
Grid.Row="0"
Grid.Column="6"
Grid.ColumnSpan="2"
VerticalAlignment="Center"
IsSnapToTickEnabled="True"
Maximum="30"
Minimum="17"
TickFrequency="1"
Value="{Binding Minimum, RelativeSource={RelativeSource Self}, Mode=OneTime}" />
<DataGrid
x:Name="PART_MyDataGrid1"
Grid.Row="1"
Grid.RowSpan="11"
Grid.Column="0"
Grid.ColumnSpan="12"
AutoGenerateColumns="True"
CanUserReorderColumns="True"
CanUserResizeColumns="True"
CanUserResizeRows="True"
CanUserSortColumns="True"
ColumnHeaderStyle="{DynamicResource ColumnHeaderStyleT11}"
ColumnWidth="SizeToHeader"
ItemsSource="{Binding MyList}">
</DataGrid>
Hallo,
vielen Dank für die Antwort.
**SizeToHeader ** habe ich bereits versucht aber leider ohne Auswirkung.
Die Spaltenbreite ist zwar initial auf die Breite des Headertextes angepasst, bei Änderung der Textgröße besteht mein beschriebenes Problem aber weiterhin.
Die Textgröße wird durch den Regler live angepasst, die Spalte wird auch live breiter, aber nicht mehr schmäler.
Ein weiteres Problem was ich durch **SizeToHeader **dann habe ist, dass der Inhalt in den einzelnen Zellen, wenn dieser länger ist als der Header, abgeschnitten ist.
Liebe Grüße
Anna
Hallo ihr Lieben,
ich habe ein Problem mit dem 'DataGrid' und finde dazu im Internet nichts brauchbares.
Ich hoffe ihr könnt mir helfen 🙂
Ich habe einen 'Slider' mit dem ich im 'DataGridColumnHeader' die Größe des Textes ändern kann.
Wenn ich den Text größer mache werden die Spalten automatisch vergrößert.
Wenn ich den Text dann wieder kleiner mache bleiben die Spalten aber vergrößert.
Die Spalten werden nicht automatisch wieder kleiner.
Wie kann ich das (am besten im Style, alternativ im Code) zum funktionieren bringen?
Es müsste unabhängig davon funktionieren ob ich die 'Columns' direkt im XAML definiere oder ob diese mit 'AutoGenerateColumns' automatisch erstellt werden.
Vielen Dank schonmal an euch
Liebe Grüße
Anna
Guten Morgen ihr Lieben 🙂
Ich bin neu hier und hoffe, dass ich bei meiner ersten Frage alles richtig mache!
Ich möchte eine ähnliche Tabelle wie auf dem Bild im anhang erstellen.
Ist:
Soll:
In einem Style für DataGridColumnHeader habe ich bisschen mit RenderTransform & LayoutTransform herumgprobiert und durch SkewTransform & RotateTransform die Header drehen können
Allerdings ist der Text verzerrt, die Header füllen nicht den gesamten Bereich der Spalte aus, und die Header drehen sich nur innerhalb dem eigenen Spaltenbereich (siehe Beitrag 2).
Das Ziel soll sein, dass durch den Schrägen Headertext die Spalte schmaler wird, da der Inhalt der Zelle meistens sehr kurz ist.
Gibt es evtl. die Möglichkeit für die Header ein Span von 2 zu definieren?
Ich hoffe ihr könnt mir helfen und ein paar Tipps geben!
Liebe Grüße
Anna