2017-02-03 75 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

相關問題