Как вы вызываете свойства с одинаковыми именами для разных типов, которые не имеют общего интерфейса? - PullRequest
0 голосов
/ 16 октября 2010

У меня есть DataTemplate, которому нужно установить свойство IsSelected для контейнера ItemsControl (например, TreeViewItem, ListViewItem или ComboBoxItem).Тем не менее, он не знает тип контейнера, пока не будет передан ему.Поскольку IsSelected не является частью общего базового класса или интерфейса, а также не является общим свойством зависимостей, зарегистрированным в AddOwner для различных классов (Duh, MS !!! WTF нет? !!), я закончил с этим беспорядком ...

if (container is TreeViewItem) {
    (container as TreeViewItem).IsSelected = true;
    return;
}

if (container is ListBoxItem) {
    (container as ListBoxItem).IsSelected = true;
    return;
}

if (container is ComboBoxItem) {
    (container as ComboBoxItem).IsSelected = true;
    return;
}

... которая не только многословна, но и требует от меня ее изменения, если я когда-либо использую другой ItemsControl, который использует разные типы контейнеров!Не хорошо!

Конечно, я мог бы немного улучшить ее, поместив эту логику в методы расширения (черт C # за отсутствие свойств расширения !!) с именами IsContainerSelected и SetContainerSelected и поместив их в UIElement, а затем переместив приведенный выше код внутрьтам, но это просто делает снаружи аккуратнее.Внутри все еще беспорядок.

Моя единственная другая мысль - использовать отражение и искать свойство IsSelected и использовать его, если оно найдено, но я всегда опасаюсь делать подобные вещи.Однако, поскольку нет общего интерфейса или базового класса, я не совсем уверен, что у меня есть выбор.

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

Мой обходной путь - использовать присоединенное поведение, которое использует события предварительного просмотра для перехватасфокусируйтесь, прежде чем это произойдет, и установите соответствующий элемент соответствующим образом, что прекрасно работает, когда я жестко запрограммировал TreeViewItem или ListBoxItem и т. д., но я не хочу жестко кодировать тип, так как элемент управления на самом деле не должен заботиться.Так что это та часть, которая ломается.

Тьфу !!!Почему MS не зарегистрировала одно и то же присоединенное свойство или хотя бы не создала интерфейс ISelectableContainer? !!

Ответы [ 3 ]

2 голосов
/ 03 января 2011

Я прочитал ваш ответ, и он имеет смысл - в вашем случае IsSelected, очевидно, может быть частью ViewModel, и это, кажется, лучшее решение в вашем случае.

Но вы попросили дополнительного объяснения динамических функций C #. C # 4.0 теперь имеет некоторые динамические функции, которые позволяют нам создавать код, который был бы возможен только в таких языках, как Python, Ruby или JavaScript. Это, конечно, имеет свою стоимость - злоупотребление dynamic не только сделает код медленнее, но и более запутанным - потому что вы потеряете ошибки во время компиляции и IntelliSense.

Я написал простой пример, чтобы вы могли его лучше понять:

public class ClassOne
{
    public int SameProperty { get; set; }
}

public class ClassTwo
{
    public int SameProperty { get; set; }
}

public class ClassThree
{
    public string SameProperty { get; set; }
}

public partial class Form1 : Form
{
    public Form1() {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e) {
        dynamic wrapper = new ClassOne();
        wrapper.SameProperty = 5;

        wrapper = new ClassTwo();
        wrapper.SameProperty = 15;

        wrapper = new ClassThree();
        wrapper.SameProperty = "Now it is a string!";

        // And now a run-time error...
        wrapper.AnotherProperty = "And this won't work...";

    }
}

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

Конечно, этот пример очень наивен, но иногда динамический код может быть полезен - это хороший вариант, чтобы избежать явного отражения или избежать длинных операторов if...else, основанных на типе (как ваш фрагмент выше). *

1 голос
/ 16 октября 2010

Я не уверен, что полностью понимаю вашу проблему, но вы можете попробовать добавить логическое значение IsSelected к вашей модели, а затем связать это свойство с элементом управления Item, в котором он содержится.свойство в модели независимо от контейнера.

0 голосов
/ 16 октября 2010

За ответ @ mdm20 он предложил модифицировать ViewModel, что, как правило, обычно и требуется. Однако это проблема, связанная исключительно с видом (связанная с навигацией по клавиатуре), и она вообще не отражена в модели представления, и в этом случае она не должна быть.

Но это дало мне идею! Поскольку я использую пользовательский элемент управления для отображения элемента в любом элементе управления (через его шаблон данных), к которому он добавляется, этот элемент управления , естественно, имеет несколько экземпляров (каждый из которых указывает на один и тот же ViewModel экземпляр), чего я и хочу!

Поэтому вместо того, чтобы добавлять IsSelected к ViewModel, я добавил его к самому пользовательскому элементу управления, а затем просто привязал его к шаблону данных для соответствующего ItemsControl, о котором я знаю. Затем я могу при необходимости установить свойство IsSelected в выделенном фрагменте кода для пользовательского элемента управления (т. Е. Во время событий мыши предварительного просмотра и т. Д.), И базовый ItemsControl отвечает соответствующим образом! Прекрасно работает и поддерживает чистоту ViewModel, так как ни модель, ни viewmodel не должны знать об этом. IsSelected остается исключительно в пользовательском интерфейсе, который в данном конкретном случае должен быть!

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