Прикрепленное свойство списка типов, но без тега encolsed

Я следую этому ответу, но когда я закомментирую контейнер

            <tly:MyDataGridHelper.HiddenCols> 
                <!--  <tly:LabelCollection>  -->
                    <Label Name="SomeProp"/>
                    <Label Name="DisplayName"/>
                <!--</tly:LabelCollection>  -->
            </tly:MyDataGridHelper.HiddenCols> 

и я меняю только имя строки, переданной на RegisterAttached

    public static readonly DependencyProperty HiddenColsProperty =
        DependencyProperty.RegisterAttached("HiddenColsInternal", typeof(LabelCollection), typeof(MyDataGridHelper), new PropertyMetadata
        {
            PropertyChangedCallback = (obj, e) =>
            {
                var grid = (DataGrid)obj;
                if (grid != null) {
                    var arr = ((LabelCollection)e.NewValue).Cast<Label>().ToArray();
                    hidden[grid.Name] = (arr ?? new Label[0]).Select(l => l.Name).ToArray();
               }
            }
        });

но если мне нужно инициализировать коллекцию в геттере

    public static LabelCollection GetHiddenCols(DependencyObject obj)
    {
        var collection = (LabelCollection)obj.GetValue(HiddenColsProperty);
        if (collection == null) {
            collection = new LabelCollection();
            obj.SetValue(HiddenColsProperty, collection);
        }
        return collection;
    }

то мои значения (например, мои имена меток: "SomeProp" и "DisplayName") теряются. Что я делаю неправильно? Как я должен их получить?

На данный момент мой обходной путь - сохранить конверт <tly:LabelCollection> (и в этом случае все работает)


person Community    schedule 13.11.2017    source источник
comment
в чем проблема оставить его внутри LabelCollection?   -  person gleng    schedule 13.11.2017
comment
последний (удаленный) ответ предполагает, что ваше прикрепленное свойство не должно иметь метод SetXxx - просто удалите его. есть ли разница, если вы удалите метод Set?   -  person ASh    schedule 13.11.2017
comment
Вы не должны менять имя, на которое зарегистрирована собственность. Если вы хотите получить к нему доступ в XAML как HiddenCols, вам придется зарегистрировать его с этим именем, а также предоставить статические методы получения и установки GetHiddenCols и SetHiddenCols. Все остальное — взлом, создающий больше проблем, чем необходимо.   -  person Clemens    schedule 13.11.2017
comment
Что ж, ваш код действительно работает для меня без метода Set и HiddenColsInternal в качестве имени свойства, но я бы не рекомендовал реализовывать его таким образом. Привязка к прикрепленному свойству не будет работать. Это хак, только для сохранения одного тега XAML.   -  person Clemens    schedule 13.11.2017
comment
Как вы объявили PropertyMetadata? Ваш код кажется неполным   -  person Il Vic    schedule 13.11.2017
comment
PropertyChangedCallback вызывается только один раз, когда значение свойства изначально установлено. Позже в коллекцию добавляются только элементы, но это не меняет значение свойства HiddenCols.   -  person Clemens    schedule 13.11.2017


Ответы (2)


Между двумя версиями вашего XAML есть важное различие.

Пока

<tly:MyDataGridHelper.HiddenCols> 
    <tly:LabelCollection>
        <Label Name="SomeProp"/>
        <Label Name="DisplayName"/>
    </tly:LabelCollection>
</tly:MyDataGridHelper.HiddenCols> 

создает и заполняет новый объект коллекции, прежде чем назначать его свойству HiddenCols,

<tly:MyDataGridHelper.HiddenCols> 
    <Label Name="SomeProp"/>
    <Label Name="DisplayName"/>
</tly:MyDataGridHelper.HiddenCols> 

просто заполняет уже созданный экземпляр коллекции, который был назначен свойству перед заполнением.

Однако ваш обратный вызов PropertyChanged ожидает уже заполненную коллекцию, поэтому вы должны использовать первый вариант.

Для второго варианта тип коллекции, вероятно, мог бы реализовать интерфейс INotifyCollectionChanged, и вы могли бы прикрепить обработчик события CollectionChanged. Или вы получаете доступ к свойству позже, например. в обработчике событий Loaded.

person Clemens    schedule 13.11.2017
comment
Понятия не имею, что там делает синтаксический анализатор XAML. IMO нет особого смысла пытаться избежать создания нового экземпляра коллекции в XAML. - person Clemens; 13.11.2017

Если вы хотите избежать создания LabelCollection в своем XAML или в геттере, вам необходимо использовать общий ObservableCollection в качестве типа свойства свойства HiddenCols. Затем с «некоторым» отражением:

public static readonly DependencyProperty HiddenColsProperty =
    DependencyProperty.RegisterAttached("HiddenColsInternal", typeof(ObservableCollection<Label>), typeof(MyDataGridHelper), new PropertyMetadata
    {
        DefaultValue = GetObservableCollectionDefaultValueFactory(),
        PropertyChangedCallback = (obj, e) =>
        {
            var grid = (DataGrid)obj;
            if (grid != null)
            {
                var arr = ((LabelCollection)e.NewValue).Cast<Label>().ToArray();
                hidden[grid.Name] = (arr ?? new Label[0]).Select(l => l.Name).ToArray();
            }
        }

private static object GetObservableCollectionDefaultValueFactory()
{
    Type type = Type.GetType("MS.Internal.ObservableCollectionDefaultValueFactory`1, WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
    Type closedType = type.MakeGenericType(typeof(Label));
    ConstructorInfo constructorInfo = closedType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
    return constructorInfo.Invoke(null);
}

Я надеюсь, что это помогает.

person Il Vic    schedule 13.11.2017
comment
Вы никогда не закончите учиться! Вы правы @Clemens, мой ответ неверен - person Il Vic; 13.11.2017
comment
@Clemens, я исправил свой ответ, поразмыслив - person Il Vic; 13.11.2017
comment
Моя точка зрения остается в силе, все это только для того, чтобы избежать создания экземпляра коллекции в XAML? Мне это не нравится, извини. - person Clemens; 13.11.2017
comment
Я согласен с вами, @Clemens, это не стоит хлопот. Но, возможно, пользователю 1892538 это по какой-то причине нужно. - person Il Vic; 13.11.2017