В WPF, как добавить EventHandler для FrameworkElement, разработанного в шаблоне? - PullRequest
4 голосов
/ 25 февраля 2011

Я определил следующие DataTemplate для ListBox элементов в словаре внешних ресурсов:

<DataTemplate x:Key="MyListBoxItemTemplate" DataType="{x:Type entities:Track}">
    <StackPanel>       
        <TextBlock Text="Here's the slider:" />
        <Slider Name="MySlider" Height="23" Minimum="0" />
    </StackPanel>
</DataTemplate>

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

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

public override void OnApplyTemplate()
{
    base.OnApplyTemplate();
    // Is the following initialization even going to work!?!?
    Slider MySlider = this.FindName("MySlider") as Slider;
    SeekSlider.ValueChanged += 
        new RoutedPropertyChangedEventHandler<double>(SeekSlider_ValueChanged);
}

Но где мне написать этот метод?Применяется ли переопределение OnApplyTemplate только к ControlTemplates или мой сценарий также включен?Должен ли я предоставить ControlTemplate вместо DataTemplate?Правильно ли указано тело метода?

Пожалуйста, помогите.Благодарю.

Ответы [ 5 ]

6 голосов
/ 25 февраля 2011

Использование подхода OnApplyTemplate будет работать, если вы работаете с ControlTemplate для элемента управления. Например, если вы вложили в подкласс TextBox, вы можете сделать это как

public class MyTextBox : TextBox
{
    public override void OnApplyTemplate()
    {
        MySlider MySlider = GetTemplateChild("MySlider") as MySlider;
        if (MySlider != null)
        {
            MySlider.ValueChanged += new RoutedPropertyChangedEventHandler<double>(MySlider_ValueChanged);
        }
        base.OnApplyTemplate();
    }
    void MySlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        //...
    }
}

Однако я не думаю, что этот подход сработает в вашей ситуации. Вы можете использовать событие Loaded для ListBoxItem и найти Slider в визуальном дереве в обработчике событий

<ListBox ...>
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <EventSetter Event="Loaded" Handler="ListBoxItem_Loaded"/>
        </Style>
    </ListBox.ItemContainerStyle>
    <!--...-->
</ListBox>

Код позади

private void ListBoxItem_Loaded(object sender, RoutedEventArgs e)
{
    ListBoxItem listBoxItem = sender as ListBoxItem;
    Slider MySlider = GetVisualChild<Slider>(listBoxItem);
    MySlider.ValueChanged += new RoutedPropertyChangedEventHandler<double>(MySlider_ValueChanged);
}
void MySlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{

}

GetVisualChild

private static T GetVisualChild<T>(DependencyObject parent) where T : Visual
{
    T child = default(T);

    int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < numVisuals; i++)
    {
        Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
        child = v as T;
        if (child == null)
        {
            child = GetVisualChild<T>(v);
        }
        if (child != null)
        {
            break;
        }
    }
    return child;
}
3 голосов
/ 25 февраля 2011

Малоизвестно, что ResourceDictionaries могут также содержать CodeBehind ..

Как общее практическое правило, я не думаю, что начинать с DataTemplates в ResourceDictionaries - это хорошая идея для начала (ваш вопроспример по одной из причин), вот как вы можете решить:

XAML:

<ResourceDictionary 
    x:Class="WpfApplication24.Dictionary1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <DataTemplate x:Key="MyDataTemplate">
        <StackPanel>
        <TextBlock Text="Hello" />
            <Slider ValueChanged="ValueChanged"/>
        </StackPanel>
    </DataTemplate>
</ResourceDictionary>

и код позади:

namespace WpfApplication24
{
    public partial class Dictionary1 : ResourceDictionary
    {

        public void ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            Debug.Write("Hello");
        }

    }
}

В любом случае, как Meleakсказал выше - OnApplyTemplate относится только к шаблонам управления, а не к шаблонам данных.

0 голосов
/ 22 декабря 2014

Метод 1 : Используйте свой собственный элемент управления, унаследованный от Slider:

public class SpecialSlider : Slider
{
    public SpecialSlider()
    {
        ValueChanged += OnValueChanged;
    }

    private void OnValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        // ...
    }
}  

Метод 2 : использовать поведения из сборки System.Windows.Interactivity.dll (доступно через NuGet):

public class SpecialSliderBehavior : Behavior<Slider>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.ValueChanged += OnValueChanged;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.ValueChanged -= OnValueChanged;
    }

    private void OnValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        // ...
    }
}

Вот как это прикрепить:

...
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
...
<DataTemplate x:Key="MyListBoxItemTemplate" DataType="{x:Type entities:Track}">
    <Slider Name="MySlider">
        <i:Interaction.Behaviors>
            <SpecialSliderBehavior />
        </i:Interaction.Behaviors>
    </Slider>
</DataTemplate>
0 голосов
/ 27 мая 2012

Вы можете использовать EventSetter в стиле, с которым вы устанавливаете шаблон:

<Style TargetType="{x:Type ListBoxItem}">
      <EventSetter Event="MouseWheel" Handler="GroupListBox_MouseWheel" />
      <Setter Property="Template" ... />
</Style>
0 голосов
/ 25 февраля 2011
...