Можно ли привязать данные к методу расширения?

Отсутствие вопросов по этому вопросу может быть признаком запаха кода здесь, но... Можно ли написать метод расширения для класса и привязать данные к этому, как если бы вы были свойством?

Предполагается, что мне предоставлена ​​структура класса, которую я не могу кардинально изменить, но я хочу выразить ряд ее логических свойств в виде строки для целей отображения.

Упрощенный базовый класс:

public class Transmission
{
    public int ID { get; set; }
    public bool Cancelled { get; set; }
    public bool Stored { get; set; }
    public bool Recorded { get; set; }
}

Мой метод расширения:

public static class Extensions
{
    public static string Status(this Transmission trans)
    {
        StringBuilder sb = new StringBuilder("|");
        if (trans.Cancelled)
            sb.Append("| Cancelled ");
        if (trans.Recorded)
            sb.Append("| Recorded ");
        if (trans.Stored)
            sb.Append("| Stored ");
        sb.Append("||");

        return sb.ToString();
    }
}

Чтобы добавить дополнительную сложность, мне передают список этих вещей, и я пытаюсь привязать к сетке данных (с сильно ограниченным опытом XAML).

<GroupBox Header="Here is an amazing list of results for you to violate horribly.">
    <DataGrid ItemsSource="{Binding Transmissions, Mode=OneWay}" AutoGenerateColumns="False">
         <DataGrid.Columns>
            <DataGridTextColumn Width="*" Header="Local ID" Binding="{Binding ID, Mode=OneWay}"/>
            <DataGridTextColumn Width="*" Header="Status" Binding="{Binding Status, Mode=OneWay}"/>
         </DataGrid.Columns>
    </DataGrid>
</GroupBox>

Я проверил код и смог без проблем привязать его к ID. "Статус", однако, не поднимается вообще. Есть ли хитрость для привязки к свойству расширения? Или было бы разумнее написать класс декоратора / фасада и связать его с этим?

2 ответа

Решение

Когда вам передают список объектов Transmission, вы можете использовать шаблон Façade и сохранять их в контейнере, предназначенном для...

public class TransmissionContainer : INotifyPropertyChanged
{
    private readonly Transmission _transmission;
    public TransmissionContainer(Transmission transmission)
    {
        _transmission = transmission;
    }
    private int _id;
    public int Id
    {
        [DebuggerStepThrough]
        get { return _transmission.ID; }
        [DebuggerStepThrough]
        set
        {
            if (value != _transmission.ID)
            {
                _transmission.ID = value;
                OnPropertyChanged("Id");
            }
        }
    }
    public bool Cancelled
    {
        [DebuggerStepThrough]
        get { return _transmission.Cancelled }
        [DebuggerStepThrough]
        set
        {
            if (value != _transmission.Cancelled)
            {
                _transmission.Cancelled = value;
                OnPropertyChanged("Cancelled");
                OnPropertyChanged("Status");
            }
        }
    }
    public string Status
    {
        [DebuggerStepThrough]
        get
        {
            StringBuilder sb = new StringBuilder("|");
            if (_transmission.Cancelled)
                sb.Append("| Cancelled ");
            if (_transmission.Recorded)
                sb.Append("| Recorded ");
            if (_transmission.Stored)
                sb.Append("| Stored ");
            sb.Append("||");
            return sb.ToString();
        }
    }
    //
    // code in other properties here
    //
    #region INotifyPropertyChanged Implementation
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string name)
    {
        var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
    #endregion
}

Это контейнерный класс, который создает фасад, к которому ваш Xaml может прозрачно привязаться. Как показано, каждое из представленных свойств просто возвращает значение в частном экземпляре Transmission. Изменения передаются в механизм привязки WPF через интерфейс INotifyPropertyChanged.

Чтобы создать экземпляр, вы можете создать его с помощью исходного класса Transmission. Чтобы связать коллекцию этих контейнеров, вы можете объявить ObservableCollection типа TransmissionContainer. Это означает, что список связан с различными изменениями в свойствах.

В этом подходе ваше свойство extension является просто еще одним доступным свойством, которое не имеет установщика. Обратите внимание, что изменения в других членах, которые влияют на Status, вызывают уведомление от имени свойства extension. Кодирование оставшихся членов класса Transmission должно занять около 20 минут...

Это то, для чего вы обычно используете шаблон, такой как MVVM. Вы добавляете в модель представления свойства, основанные на модели и относящиеся только к представлению. Модель представления может содержать ссылку на модель для привязки непосредственно к ее свойствам или для отражения их в модели представления (для развязки я бы выбрал последнее).

Другие вопросы по тегам