Можете ли вы иметь установщик событий, связанный с событием контекста данных?
Я пытаюсь создать что-то вроде этого -
У меня есть заметная коллекция очков. У каждой точки есть позиция и цвет. Когда изменяется положение точек или цвет (они меняют уведомления), я хочу "перекрасить" градиент фона. В настоящее время у меня есть элемент управления, где у меня есть ползунки, связанные с положением точек, и градиент изначально рисуется. Теперь я хочу знать, как я могу вызвать функцию в коде позади моего представления, когда происходит событие propertychange в "точке", чтобы я мог перерисовать градиент. Мне интересно, можно ли как-то использовать установщик событий?
В то время как я мог сделать подписку на событие, измененное в собственность, в коде позади, я хотел бы сделать это в XAML?
ПОЖАЛУЙСТА, ОБРАТИТЕ ВНИМАНИЕ: Я специально хочу использовать этот подход для ручной перерисовки кода по другим причинам, поэтому, если я мог бы получить ответы на конкретную проблему выше, а не альтернативные решения, пожалуйста.
1 ответ
Я думаю, вы можете создать вложенное свойство, чтобы подписаться на PropertyChanged
события значения DataContext
имущество.
public static class Props
{
public static DependencyProperty OnPropertyChangedProperty = DependencyProperty.RegisterAttached(
"OnPropertyChanged", typeof(PropertyChangedEventHandler), typeof(Props),
new PropertyMetadata(OnPropertyChangedPropertyChanged));
public static PropertyChangedEventHandler GetOnPropertyChanged (DependencyObject d)
{
return (PropertyChangedEventHandler)d.GetValue(OnPropertyChangedProperty);
}
public static void SetOnPropertyChanged (DependencyObject d, PropertyChangedEventHandler value)
{
d.SetValue(OnPropertyChangedProperty, value);
}
private static void OnPropertyChangedPropertyChanged (DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var inpc = (INotifyPropertyChanged)((FrameworkElement)d).DataContext;
if (inpc == null)
throw new ArgumentException("DataContext of the framework element must not be null.");
var oldChanged = (PropertyChangedEventHandler)e.OldValue;
if (oldChanged != null)
inpc.PropertyChanged -= oldChanged;
var newChanged = (PropertyChangedEventHandler)e.NewValue;
if (newChanged != null)
inpc.PropertyChanged += newChanged;
}
}
Использование:
<Window x:Class="So17382721PropertyChangedXaml.MainWindow" x:Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:So17382721PropertyChangedXaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:Foo}">
<!-- Here, we subscribe to DataContext.PropertyChanged;
handler is defined in the MainWindow class -->
<Grid local:Props.OnPropertyChanged="{Binding FooPropertyChanged, ElementName=root}">
<TextBox Text="{Binding Bar, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding Foos, ElementName=root}"/>
</Grid>
</Window>
Код-за:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace So17382721PropertyChangedXaml
{
public partial class MainWindow
{
public ObservableCollection<Foo> Foos { get; private set; }
public MainWindow ()
{
Foos = new ObservableCollection<Foo> {
new Foo { Bar = "1" },
new Foo { Bar = "2" },
new Foo { Bar = "3" },
};
InitializeComponent();
}
private void OnFooPropertyChanged (object sender, PropertyChangedEventArgs e)
{
MessageBox.Show(this, string.Format("{0} of {1} changed.", e.PropertyName, sender));
}
// Subscribing to non-RoutedEvents in XAML is not straightforward, but we can define a property
public PropertyChangedEventHandler FooPropertyChanged
{
get { return OnFooPropertyChanged; }
}
}
public class Foo : INotifyPropertyChanged
{
private string _bar;
public string Bar
{
get { return _bar; }
set
{
_bar = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged ([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Примечание: прикрепленное свойство Props.OnPropertyChanged
ожидает, что DataContext
не изменяется при жизни и уже указан. обращение DataContextChanged
События оставляются в качестве вычеркивания, если вам это нужно.