2017-02-03 92 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而不是示例中的Button。

+0

我在WPF和InkCanvas工作。我需要去办公室,但是我认为我不能访问InkPresenter或中风。已选中? –

+0

是的。您可以使用行为以及附加属性。使用行为和附加属性的唯一区别是你使用它们的原因。例如,Grid.Row是附加在一个控件上的东西,如果控件包含在一个网格中,它就变为活动的,类似于ScrollViewer.Horizo​​ntalScrollbarVisibility等等。 如果我们想要在某些现有控件中添加某些功能,我们通常会使用行为。因此,我的建议是采取行为。但附加的财产也会做好工作..干杯:) :) 很高兴你有一个解决方案:) :) – undefined

相关问题