2016-06-03 13 views
2

В названии говорится, что я пытаюсь сделать. Вот что у меня есть:Как включить/отключить присоединенное поведение с использованием свойства boolean в ViewModel

Я используюВклад CodeProject для приведения поведения RubberBand в ListBox, чтобы я мог перетаскивать мышью с помощью мыши. Я смог изменить его, так что я могу отключить его во время создания экземпляра ListBox, когда мне нужно, чтобы ListBox был неинтерактивным и отображал только элементы.

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

Я связал присоединенное свойство IsActive, которое я добавил в моей модифицированной RubberBand-версии (см. Код ниже) к свойству IsEditable моего UserControl-ViewModel, но по какой-то причине метод IsActiveProperty_Changed не выполняется, когда изменяется значение «IsEditable».

Это я использую поведение и связывание с «IsEditable»:

<i:Interaction.Behaviors> 
    <behavior:RubberBandBehavior IsActive="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.IsEditable}"/> 
</i:Interaction.Behaviors> 

Я также попытался это, который также не работает:

<behavior:RubberBandBehavior IsActive="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.IsEditable, UpdateSourceTrigger=PropertyChanged}"/> 

Чтобы отключить определение скорости попадания из ListBox, я также привязка к 'IsEditable', который делает работы штраф:

 <ListBox.ItemContainerStyle> 
      <Style TargetType="{x:Type ListBoxItem}"> 

       <Style.Triggers> 
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.IsEditable}" Value="False"> 
         <Setter Property="IsHitTestVisible" Value="False" /> 
         <Setter Property="Focusable" Value="False" /> 
        </DataTrigger> 
       </Style.Triggers> 
      </Style> 
     </ListBox.ItemContainerStyle> 

Поэтому я подозреваю, что это связано с моей реализацией/модификацией RubberBandBehavior, поскольку я все еще не ознакомлен с реализацией Attached Properties. Надеюсь, кто-то может заметить мою ошибку.

Модифицированные RubberBandBehavior.cs

public class RubberBandBehavior : Behavior<ListBox> 
{ 
    private RubberBandAdorner band; 
    private AdornerLayer adornerLayer; 

    public static readonly DependencyProperty IsActiveProperty = 
     DependencyProperty.Register("IsActive", typeof(bool), typeof(RubberBandBehavior), 
     new PropertyMetadata(IsActiveProperty_Changed)); 

    private static void IsActiveProperty_Changed(DependencyObject sender, 
     DependencyPropertyChangedEventArgs args) 
    { 
     RubberBandBehavior rubberBandBehavior = (RubberBandBehavior)sender; 

     if (args.Property.Name == "IsActive") 
     { 
      bool newIsActiveValue = (bool)args.NewValue; 
      bool oldIsActiveValue = (bool)args.OldValue; 

      if (newIsActiveValue != oldIsActiveValue) 
      { 
       rubberBandBehavior.IsActive = newIsActiveValue; 

       if (rubberBandBehavior.AssociatedObject != null) 
       { 
        if (newIsActiveValue == true) 
        { 
         rubberBandBehavior.AttachBehavior(); 
        } 
        else 
        { 
         rubberBandBehavior.DetachBehavior(); 
        } 
       } 
      } 
     } 
    } 

    public bool IsActive 
    { 
     get { return (bool)GetValue(IsActiveProperty); } 
     set { SetValue(IsActiveProperty, value); } 
    } 

    protected override void OnAttached() 
    { 
     AssociatedObject.Loaded += new System.Windows.RoutedEventHandler(AssociatedObject_Loaded); 
     base.OnAttached(); 
    } 

    void AssociatedObject_Loaded(object sender, System.Windows.RoutedEventArgs e) 
    { 
     if (IsActive == true) 
     { 
      AttachBehavior(); 
     } 
    } 

    protected override void OnDetaching() 
    { 
     AssociatedObject.Loaded -= new System.Windows.RoutedEventHandler(AssociatedObject_Loaded); 
     base.OnDetaching(); 
    } 

    private void AttachBehavior() 
    { 
     band = new RubberBandAdorner(AssociatedObject); 
     adornerLayer = AdornerLayer.GetAdornerLayer(AssociatedObject); 
     adornerLayer.Add(band); 
    } 

    private void DetachBehavior() 
    { 
     adornerLayer.Remove(band); 
    } 
} 

RubberBandAdorner.cs:

public class RubberBandAdorner : Adorner 
{ 
    private Point startpoint; 
    private Point currentpoint; 
    private Brush brush; 
    private bool flag; 
    private ScrollViewer viewer; 
    private ScrollBar scrollbar; 

    public RubberBandAdorner(UIElement adornedElement) 
     :base(adornedElement) 
    { 
     IsHitTestVisible = false; 
     adornedElement.MouseMove += new MouseEventHandler(adornedElement_PreviewMouseMove); 
     adornedElement.MouseLeftButtonDown += new MouseButtonEventHandler(adornedElement_PreviewMouseLeftButtonDown); 
     adornedElement.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(adornedElement_PreviewMouseLeftButtonUp); 
     brush = new SolidColorBrush(SystemColors.HighlightColor); 
     brush.Opacity = 0.3; 
    } 

    void adornedElement_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) 
    { 
     DisposeRubberBand(); 
    } 

    void adornedElement_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
    { 
     ListBox _selector = AdornedElement as ListBox; 
     if (_selector.SelectedItems != null && (_selector.SelectionMode == SelectionMode.Extended || _selector.SelectionMode == SelectionMode.Multiple)) 
     { 
      _selector.SelectedItems.Clear(); 
     } 
     startpoint = Mouse.GetPosition(this.AdornedElement); 
     Mouse.Capture(_selector); 
     flag = true; 
    } 

    public static childItem FindVisualChild<childItem>(DependencyObject obj) 
    where childItem : DependencyObject 
    { 
     // Search immediate children first (breadth-first) 
     for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) 
     { 
      DependencyObject child = VisualTreeHelper.GetChild(obj, i); 

      if (child != null && child is childItem) 
       return (childItem)child; 

      else 
      { 
       childItem childOfChild = FindVisualChild<childItem>(child); 

       if (childOfChild != null) 
        return childOfChild; 
      } 
     } 

     return null; 
    } 

    void adornedElement_PreviewMouseMove(object sender, MouseEventArgs e) 
    { 
     if (e.LeftButton == MouseButtonState.Pressed && flag) 
     { 
      currentpoint = Mouse.GetPosition(AdornedElement); 

      Selector _selector = AdornedElement as Selector; 
      if (viewer == null) 
      { 
       viewer = FindVisualChild<ScrollViewer>(_selector); 
      } 

      if (scrollbar == null) 
      { 
       scrollbar = FindVisualChild<ScrollBar>(viewer); 
      } 

      if (_selector.Items.Count > 0) 
      { 
       if (currentpoint.Y > ((FrameworkElement)AdornedElement).ActualHeight && viewer.VerticalOffset < _selector.ActualHeight && scrollbar.Visibility == System.Windows.Visibility.Visible) 
       { 
        startpoint.Y -= 50; 
       } 
       else if (currentpoint.Y < 0 && viewer.VerticalOffset > 0 && scrollbar.Visibility == System.Windows.Visibility.Visible) 
       { 
        startpoint.Y += 50; 
       } 
      } 

      InvalidateVisual(); 

      foreach (var obj in _selector.Items) 
      { 
       ListBoxItem item = _selector.ItemContainerGenerator.ContainerFromItem(obj) as ListBoxItem; 
       if (item != null) 
       { 
        Point point = item.TransformToAncestor(AdornedElement).Transform(new Point(0, 0)); 
        Rect bandrect = new Rect(startpoint, currentpoint); 
        Rect elementrect = new Rect(point.X, point.Y, item.ActualWidth, item.ActualHeight); 
        if (bandrect.IntersectsWith(elementrect)) 
        { 
         item.IsSelected = true; 
        } 
        else 
        { 
         item.IsSelected = false; 
        } 
       } 
      } 
     } 
    } 

    protected override void OnRender(DrawingContext drawingContext) 
    { 
     Rect rect = new Rect(startpoint, currentpoint); 
     drawingContext.DrawGeometry(brush, new Pen(SystemColors.HighlightBrush, 1), new RectangleGeometry(rect)); 
     base.OnRender(drawingContext); 
    } 

    private void DisposeRubberBand() 
    { 
     currentpoint = new Point(0, 0); 
     startpoint = new Point(0, 0); 
     AdornedElement.ReleaseMouseCapture(); 
     InvalidateVisual(); 
     flag = false; 
    } 
} 

Update:

Вот код IsEditable свойство ViewModel. Обратите внимание, что я использую метод RaisePropertyChanged из MvvmLight:

private bool isEditable; 
public bool IsEditable 
{ 
    get { return isEditable; } 
    set { 
     if(value != isEditable) 
     { 
      isEditable = value; 
      RaisePropertyChanged("IsEditable"); 
     } 
    } 
} 

ответ

0

Ваша проблема заключается в том, что IsActive НЕ является AttachedProperty, просто обычный DependencyProperty.

Удалить DP.Этот код должен быть удален:

public static readonly DependencyProperty IsActiveProperty = 
     DependencyProperty.Register("IsActive", typeof(bool), typeof(RubberBandBehavior), 
     new PropertyMetadata(IsActiveProperty_Changed)); 

public bool IsActive 
{ 
    get { return (bool)GetValue(IsActiveProperty); } 
    set { SetValue(IsActiveProperty, value); } 
} 

А затем добавьте IsActive как вложенное свойство:

public static bool GetIsActive(DependencyObject obj) 
{ 
    return (bool)obj.GetValue(IsActiveProperty); 
} 
public static void SetIsActive(DependencyObject obj, bool value) 
{ 
    obj.SetValue(IsActiveProperty, value); 
} 
public static readonly DependencyProperty IsActiveProperty = 
    DependencyProperty.RegisterAttached("IsActive", typeof(bool), typeof(RubberBandBehavior), new PropertyMetadata(IsActiveProperty_Changed)); 

Вы должны изменить код, который параметр/получая IsActive, а также:

rubberBandBehavior.IsActive = newIsActiveValue; 

будет

rubberBandBehavior.SetValue(RubberBandBehavior.IsActiveProperty, newIsActiveValue); 

И

if (IsActive == true) 

становится

if (this.GetValue(IsActiveProperty).Equals(true)) 

Хотя, следует отметить, что это не является необходимым для выполнения SetValue линии, так как это уже будет установлен в newIsActiveValue ... ничего, но не должно быть больно он тоже ничего не делает. Также нет необходимости проверять, отличаются ли старые и новые значения, если они не были разными, а IsActiveProperty_Changed не был бы вызван.

Edit:

Вот полный RubberBandBehavior.cs:

public class RubberBandBehavior : Behavior<ListBox> 
{ 
    private RubberBandAdorner band; 
    private AdornerLayer adornerLayer; 

    public static bool GetIsActive(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(IsActiveProperty); 
    } 
    public static void SetIsActive(DependencyObject obj, bool value) 
    { 
     obj.SetValue(IsActiveProperty, value); 
    } 
    public static readonly DependencyProperty IsActiveProperty = 
     DependencyProperty.RegisterAttached("IsActive", typeof(bool), typeof(RubberBandBehavior), new PropertyMetadata(IsActiveProperty_Changed)); 

    private static void IsActiveProperty_Changed(DependencyObject sender, 
     DependencyPropertyChangedEventArgs args) 
    { 
     RubberBandBehavior rubberBandBehavior = (RubberBandBehavior)sender; 
     if (args.Property.Name == "IsActive") 
     { 
      bool newIsActiveValue = (bool)args.NewValue; 
      if (rubberBandBehavior.AssociatedObject != null) 
      { 
       if (newIsActiveValue == true) 
       { 
        rubberBandBehavior.AttachBehavior(); 
       } 
       else 
       { 
        rubberBandBehavior.DetachBehavior(); 
       } 
      } 
     } 
    } 

    protected override void OnAttached() 
    { 
     AssociatedObject.Loaded += new System.Windows.RoutedEventHandler(AssociatedObject_Loaded); 
     base.OnAttached(); 
    } 

    void AssociatedObject_Loaded(object sender, System.Windows.RoutedEventArgs e) 
    { 
     if (this.GetValue(IsActiveProperty).Equals(true)) 
     { 
      AttachBehavior(); 
     } 
    } 

    protected override void OnDetaching() 
    { 
     AssociatedObject.Loaded -= new System.Windows.RoutedEventHandler(AssociatedObject_Loaded); 
     base.OnDetaching(); 
    } 

    private void AttachBehavior() 
    { 
     band = new RubberBandAdorner(AssociatedObject); 
     adornerLayer = AdornerLayer.GetAdornerLayer(AssociatedObject); 
     adornerLayer.Add(band); 
    } 

    private void DetachBehavior() 
    { 
     adornerLayer.Remove(band); 
    } 
} 

RubberBandAdorner в использовании ContainerFromItem, который не будет работать, если ваши детали одинаковы (список строк с одинаковым текстом, для пример). Я изменил код для использования ContainerFromIndex. Внешний foreach был изменен на цикл for.

В RubberBandAdorner.cs, в adornedElement_PreviewMouseMove обновление метод части кода следующим образом:

//foreach (var obj in _selector.Items) 
//{ 
// ListBoxItem item = _selector.ItemContainerGenerator.ContainerFromItem(obj) as ListBoxItem; 
for (int i=0; i<_selector.Items.Count; i++) 
{ 
    ListBoxItem item =_selector.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem; 
    if (item != null) 
    { 
     Point point = item.TransformToAncestor(AdornedElement).Transform(new Point(0, 0)); 
     Rect bandrect = new Rect(startpoint, currentpoint); 
     Rect elementrect = new Rect(point.X, point.Y, item.ActualWidth, item.ActualHeight); 
     if (bandrect.IntersectsWith(elementrect)) 
     { 
      item.IsSelected = true; 
     } 
     else 
     { 
      item.IsSelected = false; 
     } 
    } 
} 
+0

Привет. Прежде всего: Спасибо за ответ. К сожалению, он все еще не работает. После внесения изменений, как вы предположили, что отключение продолжает работать, как описано в моем вопросе, но метод 'IsActiveProperty_Changed' по-прежнему не срабатывает, когда« IsEditable »изменяется, и поэтому RubberBand не отключен/включен. Любые идеи, что еще может быть проблемой? – packoman

+0

Я обновил свой вопрос с помощью определения свойства IsEditable для полноты и удостоверился, что он не является виновником. – packoman

+0

Я обновил свой ответ с кодом для RubberBandBehavior.cs. Он работает для меня, я не могу сказать, почему он не работает для вас, не видя всего кода. –