Ajustar programáticamente el número de filas en una cuadrícula con C #

AEvers

Actualmente estoy aprendiendo XAML / C # y escribiendo una aplicación de calendario. En este momento está creando una cuadrícula y luego aplicando elementos de control de usuario a la cuadrícula. Está construyendo correctamente mi calendario pero, en lugar de definir el número de filas en XAML, quiero poder establecer el número a través de C # dinámicamente. Algunos meses usan más o menos semanas (marzo necesita 5 pero abril necesita 6). Me pregunto cómo hacer eso o si debería usar un control diferente al de la cuadrícula.

Así es como se ve la interfaz de usuario.

Código XAML

<UserControl x:Class="CMS.Control.MonthView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">

    <Grid VerticalAlignment="Stretch">
        <Grid.RowDefinitions>
            <RowDefinition Height="40"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Background="AliceBlue">
            <Image x:Name="MonthPrev" Source="/Images/Previous.png" Height="24" Margin="16,0,6,0" MouseLeftButtonUp="MonthPrev_MouseLeftButtonUp"/>
            <Image x:Name="MonthNext" Source="/Images/Next.png" Height="24" Margin="6,0,16,0" MouseLeftButtonUp="MonthNext_MouseLeftButtonUp"/>
            <Label x:Name="DateLabel" Content="January 2017" FontSize="16" FontFamily="Bold" VerticalAlignment="Center"/>
        </StackPanel>
        <Grid Grid.Row="1" Background="AliceBlue">
            <Grid.ColumnDefinitions>

                <ColumnDefinition MinWidth="60" Width="*"/>
                <ColumnDefinition MinWidth="60" Width="*"/>
                <ColumnDefinition MinWidth="60" Width="*"/>
                <ColumnDefinition MinWidth="60" Width="*"/>
                <ColumnDefinition MinWidth="60" Width="*"/>
                <ColumnDefinition MinWidth="60" Width="*"/>
                <ColumnDefinition MinWidth="60" Width="*"/>
            </Grid.ColumnDefinitions>
            <Label Grid.Column="0" Content="Sunday" FontSize="9" Margin="2,0,0,2" Padding="0,1,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" BorderThickness="0,0,1,0"/>
            <Label Grid.Column="1" Content="Monday" FontSize="9" Margin="2,0,0,2" Padding="0,1,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" BorderThickness="0,0,1,0"/>
            <Label Grid.Column="2" Content="Tuesday" FontSize="9" Margin="2,0,0,2" Padding="0,1,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" BorderThickness="0,0,1,0"/>
            <Label Grid.Column="3" Content="Wednesday" FontSize="9" Margin="2,0,0,2" Padding="0,1,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" BorderThickness="0,0,1,0"/>
            <Label Grid.Column="4" Content="Thursday" FontSize="9" Margin="2,0,0,2" Padding="0,1,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" BorderThickness="0,0,1,0"/>
            <Label Grid.Column="5" Content="Friday" FontSize="9" Margin="2,0,0,2" Padding="0,1,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" BorderThickness="0,0,1,0"/>
            <Label Grid.Column="6" Content="Saturday" FontSize="9" Margin="2,0,0,2" Padding="0,1,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" BorderThickness="0,0,1,0"/>
        </Grid>

        <Grid x:Name="WeekRowGrid" Grid.Row="2">
            <Grid.ColumnDefinitions>

                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
        </Grid>
    </Grid>
</UserControl>

Código C #

namespace CMS.Control
{
    /// <summary>
    /// Interaction logic for MonthView.xaml
    /// </summary>
    public partial class MonthView : UserControl
    {
        private DateTime _DispayDate;

        public MonthView()
        {
            InitializeComponent();
            _DispayDate = DateTime.Now;
            DrawMonth();
        }

        //Generates the 
        private void DrawMonth()
        {
            DateTime FirstDayOfMonth = new DateTime(_DispayDate.Year, _DispayDate.Month, 1);
            int DisplayFrontPadding = (int)FirstDayOfMonth.DayOfWeek; // # of days that need to be displayed before the 1st of the month
            int DaysInDisplayMonth = DateTime.DaysInMonth(_DispayDate.Year, _DispayDate.Month);
            int DaysInDisplay = DisplayFrontPadding + DaysInDisplayMonth; 
            DaysInDisplay += 7 - DaysInDisplay%7; // Rounds up the displayed days to a multiple of 7

            DateLabel.Content = _DispayDate.ToString("MMMM") + " " + _DispayDate.Year;

            for (int i = 0; i<DaysInDisplay; i++)
            {
                DateTime DisplayDay = FirstDayOfMonth.AddDays(i - DisplayFrontPadding);
                DayBox DB = DayBox.GetDay();   // DayBox factory
                DB.DrawDay(DisplayDay);

                Grid.SetRow(DB, i / 7);
                WeekRowGrid.Children.Add(DB);
                Grid.SetColumn(DB, i%7);
            }
        }

        //Generates a calendar for the previous month on button click.
        private void MonthPrev_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            _DispayDate = _DispayDate.AddMonths(-1);
            DrawMonth();
        }

        //Generates a calendar for the next month on button click.
        private void MonthNext_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            _DispayDate = _DispayDate.AddMonths(1);
            DrawMonth();
        }
    }
}

Sé que realmente debería usar MVVM, pero todavía estoy envolviendo mi cerebro con la programación en el patrón MVVM y quiero que esto funcione. Probablemente lo refactorice una vez que me sienta más cómodo con él.

Peter Duniho

Solo quería terminar este proyecto

Comprendido. La cuestión es que la idea básica detrás de MVVM no es realmente tan difícil, y si la acepta, es probable que termine el proyecto más rápido que si continúa intentando codificar toda su interfaz de usuario. No puedo garantizar eso, por supuesto. Pero yo he pasado por lo mismo y puedo decirte que puedes pasar mucho tiempo luchando contra WPF tratando de configurar la interfaz de usuario en código subyacente explícitamente.

Sin un buen ejemplo de código mínimo, completo y verificable para empezar, no me resultó práctico replicar exactamente su interfaz de usuario. Pero aquí hay un ejemplo de código simple que muestra el enfoque básico que puede tomar para usar MVVM para crear la interfaz de usuario que desea ...

Primero, es útil tener una clase base que se implemente INotifyPropertyChangedpor usted. Simplifica mucho el texto estándar del modelo de vista:

class NotifyPropertyChangedBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void _UpdateField<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)
    {
        if (!EqualityComparer<T>.Default.Equals(field, newValue))
        {
            field = newValue;
            _OnPropertyChanged(propertyName);
        }
    }

    protected virtual void _OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Entonces, necesitaremos ver modelos. En esta interfaz de usuario, hay dos componentes básicos: la vista general y los días individuales del mes. Entonces, hice un modelo de vista para cada uno:

class DateViewModel : NotifyPropertyChangedBase
{
    private int _dayNumber;
    private bool _isCurrent;

    public int DayNumber
    {
        get { return _dayNumber; }
        set { _UpdateField(ref _dayNumber, value); }
    }

    public bool IsCurrent
    {
        get { return _isCurrent; }
        set { _UpdateField(ref _isCurrent, value); }
    }
}

y…

class MonthViewViewModel : NotifyPropertyChangedBase
{
    private readonly ObservableCollection<DateViewModel> _dates = new ObservableCollection<DateViewModel>();

    private DateTime _selectedDate;

    public DateTime SelectedDate
    {
        get { return _selectedDate; }
        set { _UpdateField(ref _selectedDate, value); }
    }

    public IReadOnlyCollection<DateViewModel> Dates
    {
        get { return _dates; }
    }

    protected override void _OnPropertyChanged(string propertyName)
    {
        base._OnPropertyChanged(propertyName);

        switch (propertyName)
        {
            case nameof(SelectedDate):
                _UpdateDates();
                break;
        }
    }

    private void _UpdateDates()
    {
        _dates.Clear();

        DateTime firstDayOfMonth = new DateTime(SelectedDate.Year, SelectedDate.Month, 1),
            firstDayOfNextMonth = firstDayOfMonth.AddMonths(1);
        int previousMonthDates = (int)firstDayOfMonth.DayOfWeek; // assumes Sunday-start week
        int daysInView = previousMonthDates + DateTime.DaysInMonth(SelectedDate.Year, SelectedDate.Month);

        // round up to nearest week multiple
        daysInView = ((daysInView - 1) / 7 + 1) * 7;

        DateTime previousMonth = firstDayOfMonth.AddDays(-previousMonthDates);

        for (DateTime date = previousMonth; date < firstDayOfNextMonth; date = date.AddDays(1))
        {
            _dates.Add(new DateViewModel { DayNumber = date.Day, IsCurrent = date == SelectedDate.Date });
        }

        for (int i = 1; _dates.Count < daysInView; i++)
        {
            _dates.Add(new DateViewModel { DayNumber = i, IsCurrent = false });
        }
    }
}

Como puede ver, hasta ahora no se ha mencionado la interfaz de usuario y, sin embargo, ya existe toda la lógica para construir las fechas correspondientes a un mes. La parte de la interfaz de usuario, el XAML, no tendrá idea de que está haciendo algo relacionado con meses o fechas. Lo más cercano que se obtiene es un invariante codificado, es decir, el número de días de una semana que se utilizan para controlar el número de columnas en el UniformGridque se mostrarán sus datos.

El XAML tiene este aspecto:

<Window x:Class="TestSO43147585CalendarMonthView.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:l="clr-namespace:TestSO43147585CalendarMonthView"
        xmlns:s="clr-namespace:System;assembly=mscorlib"
        mc:Ignorable="d"
        SizeToContent="Height"
        Title="MainWindow" Height="350" Width="525">
  <Window.DataContext>
    <l:MonthViewViewModel SelectedDate="{x:Static s:DateTime.Today}"/>
  </Window.DataContext>

  <Window.Resources>
    <DataTemplate DataType="{x:Type l:MonthViewViewModel}">
      <ItemsControl ItemsSource="{Binding Dates}">
        <ItemsControl.ItemsPanel>
          <ItemsPanelTemplate>
            <UniformGrid IsItemsHost="True" Columns="7"/>
          </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
      </ItemsControl>
    </DataTemplate>

    <DataTemplate DataType="{x:Type l:DateViewModel}">
      <Border BorderBrush="Black" BorderThickness="0, 0, 1, 0">
        <StackPanel>
          <TextBlock Text="{Binding DayNumber}">
            <TextBlock.Style>
              <p:Style TargetType="TextBlock">
                <Setter Property="Background" Value="LightBlue"/>
                <p:Style.Triggers>
                  <DataTrigger Binding="{Binding IsCurrent}" Value="True">
                    <Setter Property="Background" Value="Yellow"/>
                  </DataTrigger>
                </p:Style.Triggers>
              </p:Style>
            </TextBlock.Style>
          </TextBlock>
          <Grid Height="{Binding ActualWidth, RelativeSource={x:Static RelativeSource.Self}}"/>
        </StackPanel>
      </Border>
    </DataTemplate>
  </Window.Resources>

  <Grid>
    <ContentControl Content="{Binding}" VerticalAlignment="Top"/>
  </Grid>
</Window>

El XAML hace tres cosas:

  1. Declara un MonthViewViewModelobjeto que se utilizará como DataContextpara el Window. Un objeto en el árbol visual, es decir, los hijos de Window, heredará el contexto de su padre si no tiene ninguno propio.
  2. Declara plantillas de datos para los dos modelos de vista. Estos le dicen a WPF cómo debe representar visualmente los datos. Un modelo de vista contiene los datos que desea representar, y estos datos se referencian en la plantilla a través de la {Binding...}sintaxis. En muchos casos (por ejemplo, texto, números, valores de enumeración), puede enlazar directamente y la conversión predeterminada hará lo que desee (como es el caso anterior). De lo contrario, puede implementar el suyo IValueConvertere incorporarlo en el enlace.
  3. Proporciona un lugar para MonthViewViewModelque se muestre, al declarar a ContentControl, donde el contenido de ese control está vinculado simplemente al contexto de datos actual (una {Binding}expresión sin una ruta se vinculará a la fuente, y la fuente predeterminada es el contexto de datos actual) .

En el contexto del ContentControl, así como de los elementos individuales que se muestran en el ItemsControl, WPF buscará la plantilla que sea apropiada para el objeto de datos definido para ese contexto, y automáticamente poblará su árbol visual, vinculando las propiedades necesarias, según a ese objeto.

Hay una serie de ventajas en este enfoque, las principales son que puede describir su interfaz de usuario en lugar de tener que codificarla , y que mantiene el principio de POO de "separación de preocupaciones", que es clave para reducir el trabajo mental. carga involucrada al permitirle concentrarse en una cosa a la vez, en lugar de tener que lidiar con la interfaz de usuario y la lógica de datos juntos.

Un par de notas al margen sobre el XAML anterior:

  • Puede notar que agregué el p:espacio de nombres XML y lo usé para el Styleelemento. Esto solo es una solución a un error de desbordamiento de pila, en el que el Styleelemento por sí mismo confunde al formateador XML y evita que el elemento y sus elementos secundarios se formatee correctamente. El XAML se compilará bien así, pero en realidad no es necesario en código real. En su XAML habitual, puede omitirlo de forma segura.
  • Incluí una característica que su código no incluía, solo con el propósito de ilustrar. Es decir, la fecha actual se resalta en amarillo. La técnica que se muestra aquí es muy útil, ya que le permite personalizar la apariencia de un elemento en una sola plantilla, según los valores de propiedad del modelo de vista. Pero hay una pequeña trampa: en WPF, si establece explícitamente la propiedad de un elemento a través de la sintaxis del atributo, por ejemplo, algo así <TextBlock Text="{Binding DayNumber}" Background="LightBlue">, esa sintaxis tendrá prioridad sobre cualquier <Setter...>elemento en un estilo. Debe recordar establecer el valor predeterminado de cualquier propiedad que desee establecer a través de un disparador, en su propio <Setter...>estilo también (como se muestra arriba).

Este artículo se recopila de Internet, indique la fuente cuando se vuelva a imprimir.

En caso de infracción, por favor [email protected] Eliminar

Editado en
0

Déjame decir algunas palabras

0Comentarios
Iniciar sesiónRevisión de participación posterior

Artículos relacionados

¿Cómo calcular () el número de filas en una plantilla de cuadrícula?

Cambiar dinámicamente el número de filas en una cuadrícula CSS

Cambiar dinámicamente el número de filas en una cuadrícula CSS

Cambiar el número de columnas y filas en una cuadrícula a medida que aumenta el número de elementos

Cambiar el número de columnas y filas en una cuadrícula a medida que aumenta el número de elementos

Necesita obtener el recuento de todas las filas en todos los grupos en una cuadrícula con agregación

Obtener las coordenadas X e Y con el número de celda en una cuadrícula

¿Cómo obtener el valor de un cuadro combinado escrito programáticamente en una cuadrícula de datos en wpf?

Cuadrícula de kendo ¿cómo puedo ajustar automáticamente el tamaño de una altura de fila de exportación de Excel?

Cómo ajustar crossAxisCount (en la vista de cuadrícula) según el detector de gestos

Cómo encontrar coordenadas con número de celda en una cuadrícula

¿Cómo crear una cuadrícula dinámica con un número par de filas y columnas?

Encaja una cuadrícula en un div sea cual sea el número de filas y columnas

¿Cómo elimino el color azul de las filas seleccionadas en una cuadrícula?

Cómo usar el intervalo de filas en una cuadrícula CSS

Alineación de cuadrícula automáticamente en varias filas

Problema con varias filas de encabezado de cuadrícula en una aplicación Vaadin 14 con el escaneo de classpath deshabilitado

¿Cómo puedo fusionar columnas verticalmente juntas como con el espacio de filas en HTML en una tabla de cuadrícula de iones?

crear una cuadrícula con 2 columnas y un número automático de filas en función del número de elementos de la lista

¿Cómo puedo colocar una etiqueta en el 66% superior de una cuadrícula con C #?

cómo eliminar una fila de cuadrícula con un botón en el renderizador de celdas

Cómo reemplazar el texto flotante con una imagen en lugar de una cuadrícula hexagonal

Cómo ajustar el valor de opacidad de forma incremental para cada fila a medida que las filas descienden en el diseño de cuadrícula CSS usando JavaScript

Cómo ajustar el valor de opacidad de forma incremental para cada fila a medida que las filas descienden en el diseño de cuadrícula CSS usando JavaScript

Especificar el número de filas y columnas en la cuadrícula

Especificar el número de filas y columnas en la cuadrícula

Cómo agregar filas de una vista de cuadrícula de datos a otra vista de cuadrícula de datos vacía mediante algún condicional en c #

Agregar un número vacío de filas en la vista de cuadrícula según el recuento de filas de la cuadrícula

Ponga un diseño de cuadrícula de reacción en una tabla con encabezados y filas

TOP Lista

CalienteEtiquetas

Archivo