Есть ли уникальный идентификатор для wpf UIElement?

Для регистрации действий пользователя в моих формах WPF я добавил несколько глобальных обработчиков событий.

Я хочу записать, какой именно элемент управления запускает событие, есть ли какой-то уникальный идентификатор для wpf UIElement, например ClientId в ASP.Net?


person Arsen Mkrtchyan    schedule 03.04.2012    source источник
comment
Вы пробовали свойство FrameworkElement.Name? ?   -  person DmitryG    schedule 03.04.2012
comment
Да, Дмитрий, но имя может быть пустым, я не хочу ставить имя на каждый элемент управления исключительно для целей логирования.   -  person Arsen Mkrtchyan    schedule 03.04.2012
comment
@ArsenMkrt, свойство PersistId, похоже, будь тем, что ты ищешь. Увы, сейчас он устарел и, по всей видимости, замены не имеет. Возможно, вы можете самостоятельно создать уникальные идентификаторы, в этом случае см. этот вопрос.   -  person Frédéric Hamidi    schedule 03.04.2012
comment
@ FrédéricHamidi, конечно, создание идентификатора - хорошая идея, но в сообщении, которое вы указали, идентификатор будет изменен после перезапуска приложения ... что сделает журнал непригодным для использования, и я не думаю, что есть способ сгенерировать стабильный идентификатор   -  person Arsen Mkrtchyan    schedule 03.04.2012
comment
Насколько я понимаю, XAML создает страницу, не требуя уникального идентификатора для элемента пользовательского интерфейса. В отсутствие присвоения уникального идентификатора я не думаю, что вы его найдете. GetHashCode может работать.   -  person paparazzo    schedule 03.04.2012


Ответы (7)


Почему бы вам не использовать хеш-код.

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


Редактировать

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

Я имею в виду, что вы можете хранить хеш-значение для каждого объекта во время создания журнала, но я не знаю, нравится ли мне это

person Jason Ridge    schedule 03.04.2012
comment
Я тестировал, и проблема в том, что GetHashCode () предназначен только для этого сеанса. Если вы закроете приложение и перезапустите, все элементы пользовательского интерфейса получат новые HashCodes. Но все же +1. - person paparazzo; 03.04.2012
comment
@ExitMusic, GetHashCode будет изменен как минимум после перезапуска приложения, что сделает журнал непригодным для использования ... Я хочу иметь более стабильный идентификатор - person Arsen Mkrtchyan; 03.04.2012

Кажется, я нашел ответ на свой вопрос, ответ - нет, теперь способ сделать это, как указано здесь в MSDN (http://msdn.microsoft.com/en-us/magazine/dd483216.aspx)

Обратите внимание, что определение элемента управления Window верхнего уровня не содержит атрибута Name. Это важно, потому что, как мы вскоре увидим, когда вы пишете автоматизацию тестирования, простой способ получить ссылку на элемент управления с помощью библиотеки MUIA - это получить доступ к свойству AutomationId, которое генерируется компилятором из атрибута Name элемента управления. . Элементы управления без атрибута имени XAML не получат свойство AutomationId. Эта идея представляет собой конкретный низкоуровневый пример важности рассмотрения вопросов проектирования приложений для таких вещей, как безопасность, расширяемость и автоматизация тестирования.

person Arsen Mkrtchyan    schedule 30.05.2012

Один из способов сделать это - использовать настраиваемый атрибут. Вот так...

UIElement, который вы хотите зарегистрировать (например, UserControl):

[UserInterfaceID(ID = "{F436E9B3-C2F6-4CF8-8C75-0A2A756F1C74}")]
public partial class MyUserControl : UserControl
{
    InitializeComponent();
    // or whatever...
}

Тогда вам понадобится класс настраиваемого атрибута

[System.AttributeUsage(AttributeTargets.Class)]
public class UserInterfaceIDAttribute : Attribute
{
    public Guid ID { get; set; }
}

Теперь в вашем коде вы можете сделать что-то вроде этого:

MyUserControl control = new MyUserControl();
foreach(object att in control.GetCustomAttributes(typeof(UserInterfaceAttribute),false))
{
    UserInterfaceAttribute uiAtt = (UserInterfaceAttribute)att;
    Guid theID = uiAtt.ID;
}

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

Конечно, это базовый пример, который показывает, как получить доступ к идентификатору, но вы, вероятно, захотите использовать какой-либо тип аспектно-ориентированного программирования. Я делаю именно такие вещи, используя Castle Windsor Interceptors, но это выходит за рамки этой статьи.

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

this.GetCustomAttributes(...)

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

Надеюсь это поможет.

person Ricky    schedule 20.04.2012
comment
Зачем мне атрибут? Я могу установить все свойства Name моих элементов пользовательского интерфейса, я просто хочу найти способ, не устанавливая ничего, потому что это возможно в winform - person Arsen Mkrtchyan; 21.04.2012

Вы просто смотрите на добавление Name или x:Name, чтобы _3 _ / _ 4 _ / _ 5_ предоставлял элемент управления остальной части класса с указанным именем.

<Window ...>
   <Grid>
       ...

       <!-- These controls are named, so you can access them directly by name -->
       <Button x:Name="btnMyNamedButton" ... />
       <Button Name="btnMyOtherNamedButton" ... />

       <!-- This control is not named, so you can not directly access it by name -->
       <Button ... />
   <Grid>
</Window>

public partial class MyWindow : Window
{
    public MyWindow()
    {
        InitializeComponent();

        //btnMyNamedButton can be accessed
        //btnMyOtherNamedbutton can also be accessed

        //The third button can be accessed, but not directly by name.
    }
}

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

person myermian    schedule 03.04.2012
comment
спасибо за ответ @my, но имя - это не то, что я ищу, сначала я не хочу давать имена всем элементам управления пользовательского интерфейса для ведения журнала, а во-вторых, это может быть невозможно для сетки с большим количеством элементов управления редактированием в ячейке шаблоны ... - person Arsen Mkrtchyan; 03.04.2012

Я считаю, что для регистрации действий пользователя вы можете использовать дерево автоматизации UIA и свойство AutomationElement.AutomationId, поскольку этот подход по умолчанию поддерживается всеми стандартными элементами управления пользовательского интерфейса. Многие сторонние элементы управления также поддерживают AutomationId для своих элементов (например, ячеек сетки). AutomationId полезен для создания сценариев автоматизации тестирования.

person DmitryG    schedule 03.04.2012
comment
Хмммм ... кажется, AutomationId тоже должен быть установлен, и если он не установлен, он возвращает Имя, которое в нашем случае пусто ... Я думаю, что нет способа сделать то, что я ищу ... - person Arsen Mkrtchyan; 03.04.2012


Я думаю, UIElement.Uid должно работать. Назначьте его в XAML и получите доступ к нему в коде.

<Label Uid="FirstName"/>

ИЛИ в свойстве стиля

<Setter Property="Uid" Value="SecondName"/>

Затем обратитесь к коду C #:


    if (Keyboard.FocusedElement is UIElement uiElement)
    {
        Debug.WriteLine(this, $"{uiElement.Uid}");
    }

person nkanani    schedule 19.03.2021