Действительно ли объект-отправитель MouseLeftButtonDown не передает ссылку на объект, который его вызвал? c # Silverlight - PullRequest
1 голос
/ 01 февраля 2010

Я недавно создал приложение Silverlight 3, в котором я создал несколько элементов пользовательского интерфейса в коде и добавил их динамически во время выполнения.

Я надеялся просто использовать встроенный MouseButtonEventArgs или объект отправителя, чтобы получить ссылку на экземпляр, по которому был выполнен щелчок, однако, как только я начал, я заметил, что это не так. Мне не удалось получить доступ к каким-либо свойствам объекта, который вызвал событие, и запрограммировать его.

 void myFunc(object sender, MouseButtonEventArgs e)
    {
        //Can't do this :(           
        sender.someProperty = someValueToUpdate;
        //or this
        MyClass foo = sender as MyClass;
        foo.someProperty = someValueToUpdate;

    }

В итоге я просто написал объект CustomEventArgs для передачи экземпляра, но меня удивило, что это не было поведением по умолчанию.

Может ли кто-нибудь пролить свет на то, ПОЧЕМУ объект-отправитель не содержит ссылку на объект, вызвавший событие?

Кроме того, вот что я сделал, чтобы получить этот экземпляр.

myObject.myEvent += new CustomEvent(myFunc);        
...
void myFunc(object sender, CustomEventArgs e)
            {
                 e.MyProperty = someValueToUpdate;
            }
...
     public class MyClass 
         {
            public MyProperty = 0;    
            public event CustomEvent myEvent;
            protected virtual void MyEventMethod(CustomEventArgs e)
            {
                if (myEvent != null){myEvent(this, e);}
            }  
            public MyClass ()
            {
             this.MouseLeftButtonDown += new MouseButtonEventHandler(this_MouseLeftButtonDown);
            }
            void rect_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                CustomEventArgs e2 = new CustomEventArgs(this);
                MyEventMethod(e2);
            }
        }   

     public class CustomEventArgs : EventArgs
        {
            private readonly MyClass myProperty;
            public CustomEventArgs(MyClass myProperty) { this.myProperty = myProperty; }
            public MyClass MyProperty { get { return myProperty; } }
        }
     public delegate void CustomEvent(object sender, CustomEventArgs e);

Ответы [ 2 ]

1 голос
/ 02 февраля 2010

MouseEventArgs имеет свойство OriginalSource. Это свойство this, которое содержит ссылку на объект, который его изначально вызвал.

Аргумент sender совершенно справедливо установлен для экземпляра объекта, к которому вы прикрепили обработчик события. Возможно, простой эксперимент покажет, как все это выглядит лучше. В Visual Studio создайте приложение Silverlight. Сделайте так, чтобы содержимое MainPage.xaml выглядело так: -

<UserControl x:Class="SilverlightApplication1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
   >
    <Grid x:Name="LayoutRoot" Background="White" MouseLeftButtonDown="MouseHandler">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <StackPanel x:Name="OuterPanel" MouseLeftButtonDown="MouseHandler" Margin="5">
            <StackPanel x:Name="TopPanel" MouseLeftButtonDown="MouseHandler">
                <TextBlock Text="First Top Item" />
                <TextBlock Text="Second Top Item" />
            </StackPanel>
            <StackPanel x:Name="BottomPanel" MouseLeftButtonDown="MouseHandler">
                <TextBlock Text="First Bottom Item" />
                <TextBlock Text="Second Bottom Item" />
            </StackPanel>
        </StackPanel>
        <ListBox x:Name="lstOutput" Grid.Column="1" Margin="5" />
    </Grid>
</UserControl>

И в MainPage.xaml.cs добавьте этот код: -

    private void MouseHandler(object sender, MouseButtonEventArgs e)
    {
        FrameworkElement s = sender as FrameworkElement;
        TextBlock o = e.OriginalSource as TextBlock;
        string text = (o != null) ? o.Text : "Not from a text block";
        lstOutput.Items.Add(String.Format("Sender: {0}, Text block: {1}", s.Name, text));
    }

Обратите внимание, как этот же обработчик присоединен к трем различным элементам в XAML, но не к самим TextBlocks. Нажав на «Первый топовый предмет», вы получите следующее: -

Sender: TopPanel, Text block: First Top Item
Sender: OuterPanel, Text block: First Top Item
Sender: LayoutRoute, Text block: First Top Item

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

Нажмите на область под панелями стека. Вы получаете только: -

Sender: LayoutRoot, Text block: Not from a text block

Интересно также то, что нажатие в окне списка не приводит к добавлению элементов вообще, вы можете ожидать того же, что и в приведенной выше строке. Очевидно, ListBox опускает мышь и поэтому устанавливает свойство args Handled события на True, предотвращая дальнейшее всплытие.

1 голос
/ 01 февраля 2010

Из документации MSDN:

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

т.е. так как это бурное событие, может быть, вам стоит попробовать что-то вроде

void myFunc(object sender, MouseButtonEventArgs e)
{

    var theUIElement = sender as TheUIElementOfWhichImInterested;
    if (theUIElement != null)
    {
        // set properties on the element
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...