У меня есть несколько фигур, где я хочу изменить непрозрачность, когда я нажимаю на нее, кроме того, мне нужно знать в коде, какие фигуры были выбраны, и мне нужно установить непрозрачность из кода позади.
Моя идея это использовать Dictionary<int, bool>
с индексом и если выбрано или нет. Я знаю, что Dictionary
не реализует INotifyCollectionChanged
или INotifyPropertyChanged
, но я нашел пример наблюдаемого словаря, который очень хорошо запускает оба события.
Для каждой фигуры (прямоугольника) я устанавливаю следующую привязку :
<Rectangle Height="25" Stroke="Black" Margin="10" Fill="AliceBlue" StrokeThickness="3">
<Rectangle.Style>
<Style TargetType="Rectangle">
<EventSetter Event="PreviewMouseDown" Handler="Rectangle_PreviewMouseDown"></EventSetter>
<Setter Property="local:IndexProperty.SectorIndex" Value="1"></Setter>
<Setter Property="local:SelectSectorProperty.SelectedSector" Value="{Binding SelectedRect, Mode=OneWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"></Setter>
</Style>
</Rectangle.Style>
</Rectangle>
В пределах Rectangle_PreviewMouseDown
Я переключаю значение bool ObservableDictionary<int, bool>
с помощью SectorIndex.
Присоединенное свойство выглядит следующим образом:
public class SelectSectorProperty : DependencyObject
{
public static ObservableDictionary<int, bool> GetSelectedSector(DependencyObject obj)
{
return (ObservableDictionary<int, bool>)obj.GetValue(SelectedSectorProperty);
}
public static void SetSelectedSector(DependencyObject obj, ObservableDictionary<int, bool> value)
{
obj.SetValue(SelectedSectorProperty, value);
}
// Using a DependencyProperty as the backing store for SectorList. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedSectorProperty =
DependencyProperty.RegisterAttached("SelectedSector", typeof(ObservableDictionary<int, bool>),
typeof(SelectSectorProperty), new PropertyMetadata(OnStatusChanged));
private static void OnStatusChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
Debug.WriteLine("OnStatusChanged");
if (obj is Rectangle element)
{
if (e.NewValue?.GetType() == typeof(ObservableDictionary<int, bool>))
{
var index = (int)obj.GetValue(IndexProperty.SectorIndexProperty);
GetSelectedSector(obj).TryGetValue(index, out bool selected);
if (selected)
{
element.Opacity = 0.8;
}
else
{
element.Opacity = 0.1;
}
}
}
}
}
Моя ViewModel is this:
public class ViewModel : ViewModelBase
{
public ViewModel()
{
SelectedRect.PropertyChanged += SelectedSectors_PropertyChanged;
}
private void SelectedSectors_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
OnPropertyChanged(nameof(SelectedRect));
}
private ObservableDictionary<int, bool> _SelectedRect = new ObservableDictionary<int, bool>() {
{ 1, false},
{ 2, false},
{ 3, false},
};
public ObservableDictionary<int, bool> SelectedRect
{
get { return _SelectedRect; }
set
{
_SelectedRect = value;
OnPropertyChanged(nameof(SelectedRect));
}
}
}
После обновления моего ObservableDictionary
запускается событие SelectedRect.PropertyChanged
, а также вызывается событие OnPropertyChanged
, реализованное в классе ViewModelBase
, с точно таким же параметры, которые будут вызываться из самого свойства SelectedRect
. Но OnStatusChanged
моего присоединенного свойства не сработает, только если я изменю ссылку на мое свойство SelectedRect
(например, установив значение null и вернусь к нему).
Это отличается от моих ожиданий, я бы действительно хотелось бы знать почему, достаточно вызвать OnPropertyChanged
с правильными параметрами, но кажется, что за кулисами происходит больше проверки.
Я думаю, что явное обновление Binding - это путь к go?