Можете ли вы привязать отдельные поля даты и времени к одному DateTime в C #? - PullRequest
3 голосов
/ 10 августа 2009

Наш интерфейс имеет дату и время в отдельных полях. Один ящик для даты (с DatePicker), один ящик для времени (как TextBox).

Можно ли привязать данные к единственному DateTime (или, предпочтительно, обнуляемому DateTime) для этих отдельных значений? (Если нет, какие есть альтернативы?)

Как это можно сделать?

Ответы [ 2 ]

1 голос
/ 10 августа 2009

В вашем интерфейсе создайте публичное свойство или метод для получения всей даты. Этот метод или свойство создаст дату, используя поля вашего интерфейса. То, что вы сделали, звучит как удобный интерфейс, так как четкое разделение этих двух логично.

public DateTime GetDateTime(){
    return new DateTime(DateControl.Year,DateControl.Month,DateControl.Day,TimeControl.Hour,TimeControl.Minute);
}

В качестве примера это может быть возможный метод на вашем интерфейсе, который можно использовать!

Впоследствии у вас может быть метод set, который принимает дату и время, а затем вы разделяете значения и связываете два элемента управления. : -)

Andrew

0 голосов
/ 30 апреля 2015

Да, это возможно!

Сценарий

  1. Имеют два отдельных поля DateTimePicker в пользовательском интерфейсе, одно из которых представляет дату, а другое представляет время.Пример:

DateTimePicker dtpDate;
DateTimePicker dtpTime;
Имейте модель с единственным свойством DateTime.Пример:

public class MyModel
{
    public DateTime? When;
}

Что мы пытаемся сделать?

Изменить свойство модели When автоматически при изменении любого изупомянутые элементы управления пользовательского интерфейса и наоборот;

Решение

Сделайте свой класс модели привязываемым и имеют 2 дополнительных свойства, которые действуют как мост (прокси) междусвойство When и поля, представляющие частичное DateTime значение (например: один DateTimePicker для даты и другой для времени).Эти прокси необходимы, потому что при изменении любого из элементов управления пользовательского интерфейса нам нужно знать, какие компоненты / части DateTime необходимо будет изменить.Это дата или время?

Теперь следующий код делает совсем немного.Во-первых, вы хотите реагировать на любые изменения любого из прокси (ProxyWhenDate и ProxyWhenTime), отражая это изменение в результирующем DateTime (When), и наоборот.Чтобы это работало, вам нужно сделать этот класс привязываемым.Это можно сделать, внедрив INotifyPropertyChanged и реализовав пользовательские установщики свойств, которые вызывают событие PropertyChanged с соответствующим именем свойства.

Пример:

public class MyModel : INotifyPropertyChanged
{
    #region Bindable properties

    private DateTime? _When;
    public virtual DateTime? When
    {
        get { return _When; }
        set
        {
            SetField(ref _When, value);
            // When a change to `When` occurs, it means `ProxyWhenDate` and `ProxyWhenTime` have been changed as well,
            // so we need to raise a `PropertyChanged` notification for both of them.
            NotifyPropertyChanged(this.GetPropertyName((MyModel x) => x.ProxyWhenDate));
            NotifyPropertyChanged(this.GetPropertyName((MyModel x) => x.ProxyWhenTime));
        }
    }

    #endregion

    #region Proxies

    public virtual DateTime ProxyWhenDate
    {
        get
        {
            return When.HasValue ? When.Value : DateTime.UtcNow;
        }
        set
        {
            DateTime v = When.HasValue ? When.Value : DateTime.UtcNow;
            // Change only Year + Month + Day, keeping the rest as it is.
            When = new DateTime(value.Year, value.Month, value.Day, v.Hour, v.Minute, v.Second);
        }
    }

    public virtual DateTime ProxyWhenTime
    {
        get
        {
            return When.HasValue ? When.Value : DateTime.UtcNow;
        }
        set
        {
            DateTime v = When.HasValue ? When.Value : DateTime.UtcNow;
            // Change only Hour + Minute + Second, keeping the rest as it is.
            When = new DateTime(v.Year, v.Month, v.Day, value.Hour, value.Minute, value.Second);
        }
    }

    #endregion

    #region Object extensions

    public static string GetPropertyName<TSource, TField>(this Object obj, Expression<Func<TSource, TField>> Field)
    {
        return (Field.Body as MemberExpression ?? ((UnaryExpression)Field.Body).Operand as MemberExpression).Member.Name;
    }

    #endregion

    #region Support for bindings

    public virtual event PropertyChangedEventHandler PropertyChanged;

    // NotifyPropertyChanged will raise the PropertyChanged event passing the
    // source property that is being updated.
    public virtual void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public virtual void NotifyPropertyChanged<TProperty>(Expression<Func<TProperty>> property)
    {
        var lambda = (LambdaExpression)property;
        MemberExpression memberExpression;
        if (lambda.Body is UnaryExpression)
        {
            var unaryExpression = (UnaryExpression)lambda.Body;
            memberExpression = (MemberExpression)unaryExpression.Operand;
        }
        else
        {
            memberExpression = (MemberExpression)lambda.Body;
        }
        NotifyPropertyChanged(memberExpression.Member.Name);
    }

    public virtual bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value))
            return false;

        field = value;
        NotifyPropertyChanged(propertyName);
        return true;
    }

    #endregion
}

Сейчасвсе, что вам нужно сделать, это создать привязки между свойствами элементов управления пользовательского интерфейса и свойствами вашей модели.Пример:

public partial class MyForm : Form
{
    private MyModel Model;

    public MyForm(MyModel model)
    {
        InitializeComponent();

        Model = model;

        // Create our bindings

        dtpDate.DataBindings.Add(new Binding("Value", Model,
            this.GetPropertyName((MyModel x) => x.ProxyWhenDate)));

        dtpTime.DataBindings.Add(new Binding("Value", Model,
            this.GetPropertyName((MyModel x) => x.ProxyWhenTime)));
    }
}

Готово!Наслаждайтесь волшебством и извините за опоздание на ~ 6 лет; -)

ПРИМЕЧАНИЕ. Атрибут CallerMemberName был введен в .NET Framework 4.5, но вы можете жить без него, изменив еговсего несколько строк кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...