2017-02-03 13 views
0

В стандартном шаблоне MVVM, как модель представления узнала о выбранных ударах из InkCanvas?Как передать InkCanvas SelectedStrokes в viewmodel?

В фоновом коде со знанием InkCanvas, удаление выбранных штрихов очень легко:

private void btnDeleteSelectedStrokes_Click(object sender, RoutedEventArgs e) 
     { 
      StrokeCollection selectedStrokes = theInkCanvas.GetSelectedStrokes(); 
      theInkCanvas.Strokes.Remove(selectedStrokes); 

     } 

Но это может быть сделано в MVVM?

TIA

ответ

0

Вместо лучшим решения, это работает для меня:

XAML 
xmlns:h="clr-namespace:Notepad.Helpers" 

<InkCanvas ... h:InkCanvasExtension.IsSelectionEnabled="True" 
       h:InkCanvasExtension.TheSelectedStrokes="{Binding SelectedStrokes, Mode=TwoWay}" 

Прикрепленных Свойства:

namespace Notepad.Helpers 
{ 
    public static class InkCanvasExtension 
    { 
     /*The provider class for an attached property (even if it is not registered as a dependency property) must provide static get and set accessors 
     * that follow the naming convention Set[AttachedPropertyName] and Get[AttachedPropertyName]. These accessors are required so that the acting XAML 
     * reader can recognize the property as an attribute in XAML and resolve the appropriate types.*/ 

     #region [IsSelectionEnabled] 
     public static bool GetIsSelectionEnabled(DependencyObject obj) 
     { 
      return (bool)obj.GetValue(IsSelectionEnabled); 
     } 

     public static void SetIsSelectionEnabled(DependencyObject obj, bool value) 
     { 
      obj.SetValue(IsSelectionEnabled, value); 
     } 

     // In XAML, IsSelectionEnabled = "true" will call OnIsSelectionEnabled(). 
     public static readonly DependencyProperty IsSelectionEnabled = 
      DependencyProperty.RegisterAttached("IsSelectionEnabled", 
      typeof(bool), typeof(InkCanvasExtension), 
      new UIPropertyMetadata(false, OnIsSelectionEnabled)); 


     private static void OnIsSelectionEnabled(object sender, DependencyPropertyChangedEventArgs e) 
     { 
      InkCanvas ic = sender as InkCanvas; 
      if (ic != null) 
      { 
       // get the value of IsSelectionEnabled (which is either true or false). 
       bool isEnabled = (bool)e.NewValue; 
       if (isEnabled) 
       { 
        ic.SelectionChanged += OnSelectionChanged; 
       } 
       else 
       { 
        ic.SelectionChanged -= OnSelectionChanged; 
       } 
      } 
     } 

     private static void OnSelectionChanged(object sender, EventArgs e) 
     { 
      // Assigning TheSelectedStrokes directly like: 
      //  TheSelectedStrokes = selectedStrokes 
      // will not work and will break the binding. Must use: 
      //  SetTheSelectedStrokes(ic, selectedStrokes); 

      InkCanvas ic = sender as InkCanvas; 
      StrokeCollection selectedStrokes = ic.GetSelectedStrokes(); 
      SetTheSelectedStrokes(ic, selectedStrokes); 
     } 


     #endregion 

     #region [TheSelectedStrokes] 
     public static StrokeCollection GetTheSelectedStrokes(DependencyObject obj) 
     { 
      return (StrokeCollection)obj.GetValue(TheSelectedStrokes); 
     } 

     public static void SetTheSelectedStrokes(DependencyObject obj, StrokeCollection value) 
     { 
      obj.SetValue(TheSelectedStrokes, value); 
     } 

     // by default binding works one way, i.e. loading changes from the view model, but not updating it back. 
     // so must add FrameworkPropertyMetadataOptions.BindsTwoWayByDefault to send update to the viewmodel. 
     public static readonly DependencyProperty TheSelectedStrokes = 
       DependencyProperty.RegisterAttached("TheSelectedStrokes", 
       typeof(StrokeCollection), typeof(InkCanvasExtension), 
       new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); 
     #endregion 

    } 

} 

Надеется, что это помогает кому-то.

1

Вы можете использовать поведение для его реализации.

public class InkCanvasDeleteBehavior : Behavior<Button> 
{ 
    public InkCanvas Canvas 
    { 
     get { return (InkCanvas)GetValue(CanvasProperty); } 
     set { SetValue(CanvasProperty, value); } 
    } 

    public static readonly DependencyProperty CanvasProperty = 
     DependencyProperty.Register("Canvas", 
      typeof(InkCanvas), 
      typeof(InkCanvasDeleteBehavior), 
      new PropertyMetadata(null)); 



    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     var btnDelete = this.AssociatedObject as Button; 
     if(btnDelete!=null) 
     { 
      btnDelete.Click += BtnDelete_Click; 
     } 
    } 

    private void BtnDelete_Click(object sender, RoutedEventArgs e) 
    { 
     if(this.Canvas!=null) 
     { 
      var stokeCollection = this.Canvas.InkPresenter.StrokeContainer.GetStrokes(); 
      foreach (var stroke in stokeCollection) 
      { 
       stroke.Selected = true; 
      } 
      this.Canvas.InkPresenter.StrokeContainer.DeleteSelected(); 
     } 
    } 
} 

Для XAML вы можете использовать поведение таким образом.

<Page 
x:Class="Mock.MainPage" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:local="using:Mock" 
xmlns:behavior="using:Mock.Behaviors" 
xmlns:i="using:Microsoft.Xaml.Interactivity" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
mc:Ignorable="d"> 

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="auto"/> 
     <RowDefinition Height="*"/> 
    </Grid.RowDefinitions> 
    <InkCanvas x:Name="_canvas" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="1"/> 
    <Button Content="Delete" HorizontalAlignment="Center" Margin="5"> 
     <i:Interaction.Behaviors> 
      <behavior:InkCanvasDeleteBehavior Canvas="{Binding ElementName=_canvas}"/> 
     </i:Interaction.Behaviors> 
    </Button> 
</Grid> 
</Page> 

PS: Я использую UWP. В WPF некоторый код может быть немного иным, но основная логика такая же.

Существует еще один способ сделать это, передав объект, используя параметр команды, а затем используя команду кнопки, чтобы удалить элемент. Это также сработает. Если вам нужен образец, дайте мне знать.

В дополнение к этому вы также можете использовать поведение, чтобы передать значение модели просмотра. Вы можете сохранить свойство StrokeCollection в вашей модели просмотра и передать ссылку на поведение. Когда вы рисуете что-то в InkCanvas, обновите StrokeCollection в поведении, которое будет отображаться в ViewModel.

Единственное различие заключалось бы в том, что поведение будет привязано к InkCanvas вместо кнопки в примере.

+0

Я работаю в WPF и с InkCanvas. Мне нужно добраться до офиса, но с рук не думаю, что у меня есть доступ к InkPresenter или штриху. Выбрано? –

+0

Yup. Вы можете использовать поведение, а также приложенные свойства. Единственная разница между использованием свойств поведения и Attached - причина, по которой вы их используете. Например, Grid.Row - это то, что вы прикрепляете к элементу управления, который становится активным, если элемент управления заключен в сетку, аналогично ScrollViewer.HorizontalScrollbarVisibility и другие. Обычно мы используем поведение, если хотим добавить некоторые функции в некоторый существующий элемент управления. Поэтому мое предложение состояло в том, чтобы идти с поведением. Но приложенное свойство будет делать все хорошо. Cheers :) :) Рад, что у вас есть решение :) :) – undefined

 Смежные вопросы

  • Нет связанных вопросов^_^