Ich mache eine Benutzerkontrolle für ein Datengrid. Dieses Datenraster enthält einige alte und neue Einträge. Es ist erforderlich, dass die neuen Einträge oben auf dem Bildschirm angezeigt werden, die Reihenfolge der Daten muss jedoch chronologisch sein. Also schiebe ich das ganze Raster nach oben, indem ich leere Zeilen hinzufüge. Wenn ich zum Beispiel 8 alte Einträge und 2 neue Einträge habe, müssen die 8 alten Einträge über dem ersten der beiden neuen Einträge "versteckt" werden.Holen Sie sich die tatsächliche Höhe bei Ladezeit
Um die leeren Zeilen zu berechnen, möchte ich die tatsächliche Höhe des Benutzersteuerelements durch die Zeilenhöhe teilen. Ich habe einen Weg gefunden, die tatsächliche Höhe durch eine Abhängigkeitseigenschaft zu erhalten (siehe Code unten). Ich brauche es zu Beginn, also habe ich einen Trigger implementiert, der mir Zugang zum Loader-Event gibt. Zu diesem Zeitpunkt hat das Benutzersteuerelement immer noch die Größe 0. Gibt es ein anderes Ereignis, das es mir erlauben würde, dies zum richtigen Zeitpunkt zu berechnen?
Eine letzte Anmerkung, ich verwende Galasoft MVVMLight und ein passendes MVVM-Muster. Außerdem gibt die Abhängigkeitseigenschaft die richtige Höhe, sobald Sie die Höhe des Fensters nach der ersten Initialisierung ändern.
Der Blick
<DataGrid x:Class="Kwa.Presentation.Views.AlarmList.AlarmList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Kwa.Presentation.Views.AlarmList"
xmlns:behaviors="clr-namespace:Kwa.Presentation.Behaviors"
xmlns:Trans="clr-namespace:Kwa.Presentation.Resources"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="750"
ItemsSource="{Binding Alarms}"
SelectedItem="{Binding SelectedAlarm, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectionChanged = "AlarmFramework_SelectionChanged"
IsSynchronizedWithCurrentItem="True"
CanUserResizeColumns="True" IsReadOnly="True" CanUserReorderColumns="False" CanUserSortColumns="False" SelectionMode="Single" CanUserAddRows="False"
Background="White" RowHeaderWidth="0" AutoGenerateColumns="False" GridLinesVisibility="None" RowHeight="20" FrozenColumnCount = "1"
ScrollViewer.CanContentScroll="False" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto"
x:Name="AlarmFramework"
behaviors:ElementActualSizeBehavior.ActualHeight="{Binding ListHeight}"
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding AlarmListLoadedCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<DataGrid.Columns>
<DataGridTemplateColumn Header="{x:Static Trans:TranslatedResources.AlarmColumnHeaderTime}" Width="auto" HeaderStyle="{StaticResource WithButt}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<components:FlagControl VerticalAlignment="Center" Height="15" Width="15" FlagColor="{Binding Severity, Converter={StaticResource AlarmSeverityToColorConverter}}"
Visibility="{Binding AckStatus, Converter={StaticResource InvertedBoolToVisibilityConverter}, Mode=TwoWay}"/>
<TextBlock Text="{Binding DateTimeString}" Padding="10,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="{x:Static Trans:TranslatedResources.AlarmColumnHeaderSeverity}" Binding="{Binding SeverityString}" Width="auto" HeaderStyle="{StaticResource WithoutButt}"/>
<DataGridTextColumn Header="{x:Static Trans:TranslatedResources.AlarmColumnHeaderDescription}" Binding="{Binding Description}" d:Width="400" Width="*" HeaderStyle="{StaticResource WithoutButt}"/>
</DataGrid.Columns>
</DataGrid>
Eigenschaft Dependency tatsächliche Höhe erhalten
public class ElementActualSizeBehavior
{
public static double GetActualWidth(DependencyObject obj)
{
return (double)obj.GetValue(ActualWidthProperty);
}
public static void SetActualWidth(DependencyObject obj, double value)
{
obj.SetValue(ActualWidthProperty, value);
}
public static double GetActualHeight(DependencyObject obj)
{
return (double)obj.GetValue(ActualHeightProperty);
}
public static void SetActualHeight(DependencyObject obj, double value)
{
obj.SetValue(ActualHeightProperty, value);
}
public static readonly DependencyProperty ActualWidthProperty = DependencyProperty.RegisterAttached("ActualWidth", typeof(double), typeof(ElementActualSizeBehavior), new FrameworkPropertyMetadata(double.NaN, new PropertyChangedCallback(ActualWidthChanged)) { BindsTwoWayByDefault = true });
public static readonly DependencyProperty ActualHeightProperty = DependencyProperty.RegisterAttached("ActualHeight", typeof(double), typeof(ElementActualSizeBehavior), new FrameworkPropertyMetadata(double.NaN, new PropertyChangedCallback(ActualHeightChanged)) { BindsTwoWayByDefault = true });
private static void ActualHeightChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
Control w = source as Control;
if (w != null)
{
w.SizeChanged += (se, ev) =>
{
SetActualHeight((DependencyObject)se, ev.NewSize.Height);
};
}
}
private static void ActualWidthChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
Control w = source as Control;
if (w != null)
{
w.SizeChanged += (se, ev) =>
{
SetActualWidth((DependencyObject)se, ev.NewSize.Width);
};
}
}
}
Die Ansicht Modell
public class AlarmListViewModel : MainViewModelBase
{
#region Properties
private double _listHeight;
public double ListHeight
{
get { return _listHeight; }
set
{
if (Double.IsNaN(value))
{
//Debug.WriteLine("nan");
return;
}
_listHeight = value;
//Debug.WriteLine(value);
RaisePropertyChanged(() => ListHeight);
}
}
private ObservableCollection<AlarmEntryViewModel> _alarms;
public ObservableCollection<AlarmEntryViewModel> Alarms
{
get { return _alarms; }
set { Set(() => Alarms, ref _alarms, value); }
}
private AlarmEntryViewModel _selectedAlarm;
public AlarmEntryViewModel SelectedAlarm
{
get { return _selectedAlarm; }
set { Set(() => SelectedAlarm, ref _selectedAlarm, value); }
}
private int _acknowledgeAllowed;
public int AcknowledgeAllowed
{
get { return _acknowledgeAllowed; }
set { Set(() => AcknowledgeAllowed, ref _acknowledgeAllowed, value); }
}
private int _acknowledgableAlarms;
public int AcknowledgableAlarms
{
get { return _acknowledgableAlarms; }
set { Set(() => AcknowledgableAlarms, ref _acknowledgableAlarms, value); }
}
private int _rowHeight;
public int RowHeight
{
get { return _rowHeight; }
set { Set(() => RowHeight, ref _rowHeight, value); }
}
private readonly IActionCommand _acknowledgeCommand;
public IActionCommand AcknowledgeCommand
{
get { return _acknowledgeCommand; }
}
private readonly IActionCommand _alarmListLoadedCommand;
public IActionCommand AlarmListLoadedCommand
{
get { return _alarmListLoadedCommand; }
}
public int MaxAcknowledgedAlarm;
public int AlarmToSendIndex { get; set; }
#endregion
#region Constructor
public AlarmListViewModel()
{
//Lock collection to stop inconsistent item source exception
Alarms = new ObservableCollection<AlarmEntryViewModel>();
BindingOperations.EnableCollectionSynchronization(Alarms, _AlarmsLock);
//Add command
_acknowledgeCommand = new ActionCommand<AlarmEntryViewModel>(p => Acknowledge(p));
_alarmListLoadedCommand = new ActionCommand<AlarmListViewModel>(p => Startup());
}
#endregion
#region Private Methods
private void Startup()
{
var rowsInView = (int)Math.Floor(ListHeight/RowHeight);
var rowsInAlarms = Alarms.Count;
var rowsNeeded = rowsInView - rowsInAlarms;
}
Welche Höhe möchten Sie und wo ...? Sie sollten ein * minimales * Codebeispiel bereitstellen, wenn Sie eine Frage stellen ... – mm8
Die Höhe des Datagrids in dem Moment, in dem es initialisiert wird. Ich sehe nicht, wie dies verwirrend sein kann ... –
Den Befehl im Callback der ElementActualSizeBehavior.ActualHeight -Eigenschaft auslösen? – mm8