2017-12-19 4 views
1

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; 
    } 
+0

Welche Höhe möchten Sie und wo ...? Sie sollten ein * minimales * Codebeispiel bereitstellen, wenn Sie eine Frage stellen ... – mm8

+0

Die Höhe des Datagrids in dem Moment, in dem es initialisiert wird. Ich sehe nicht, wie dies verwirrend sein kann ... –

+0

Den Befehl im Callback der ElementActualSizeBehavior.ActualHeight -Eigenschaft auslösen? – mm8

Antwort

0

Irgendwann hat mir jemand das Problem erklärt und eine Lösung gefunden. Das Problem lag darin, dass sich die Höhe/Breite des Bedienelements zur Ladezeit nicht ändert. Es bleibt relativ zu seiner Vorfahren Breite/Höhe (oder so ähnlich). Wie auch immer, deshalb erhalten Sie in Ihrem View-Modell kein Update.

Die Lösung besteht aus zwei Teilen. Zuerst muss das ElementActionSizeBehavior wie im obigen Code implementiert werden. Dann müssen Sie die Größe der Komponenten explizit deklarieren. Dies kann durch das Hinzufügen der Zeile erfolgen:

Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Control}}, Path=ActualHeight}" 

So ist die aktualisierte Ansicht Header so etwas wie dies sein sollte:

<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" 
      mc:Ignorable="d" 
      d:DesignHeight="500" d:DesignWidth="750" 
      Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Control}}, Path=ActualHeight}" 
behaviors:ElementActualSizeBehavior.ActualHeight="{Binding ListHeight}" 
      > 

Sie auch mehr die Interaktivität Teile nicht brauchen.

Hoffentlich kann dies anderen Menschen helfen, ihre tatsächlichen Höhen und Breiten zu bekommen.

Verwandte Themen