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


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

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

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

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();
    }
}

К добавьте дополнительную сложность, мне передают список этих вещей, и я пытаюсь привязаться к datagrid (с сильно ограниченным опытом 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 2

2 ответа:

Когда вы передаете список объектов передачи, вы можете использовать шаблон фасада и хранить их в специально разработанном контейнере...

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 может прозрачно привязываться. Как показано, каждое из представленных свойств просто повторяет значение в частном экземпляре передачи. Изменения передаются в механизм привязки WPF через интерфейс INotifyPropertyChanged.

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

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

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