获取所选ItemsControl项目

时间:2016-10-14 13:13:22

标签: vb.net xaml mvvm uwp windows-10-universal

当前正在创建我的Windows 10应用程序,我正在尝试按照mvvm模式在画布上移动一个矩形。下面的代码可以工作,但我在我的viewmodel PointerDragEvent中使用了一个uielemnt来破坏mvvm。

   Dim rec = TryCast(e.OriginalSource, Button)
   Dim selrecitem = TryCast(rec.DataContext, RectItem)

问题

有没有非hacky /正确的方法吗?

如何检索我点击的项目并将其传递给我的viewmodel?

画布上的所有项目都将动态创建。

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

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.DataContext>
        <local:myviewmodel/>
    </Grid.DataContext>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="8*"/>
        <RowDefinition Height="*"/>

    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="11*"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <ItemsControl x:Name="itemsControl" Grid.Column="1" Grid.Row="1" ItemsSource="{Binding myrectangles, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        <Interactivity:Interaction.Behaviors>
            <Core:EventTriggerBehavior EventName="ManipulationDelta">
                <Core:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="PointerDrag"/>
            </Core:EventTriggerBehavior>
        </Interactivity:Interaction.Behaviors>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Background="White">

                </Canvas>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.ItemTemplate>

            <DataTemplate>
                <Button x:Name="PageItem" Background="Transparent" BorderBrush="DodgerBlue" Width="{Binding Width}" Height="{Binding Height}" ManipulationMode="TranslateX, TranslateY" IsHitTestVisible="{Binding IsChecked, ElementName=SelectToolButton, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" Command="{Binding SendMyDC, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
                    <Button.RenderTransform>
                        <CompositeTransform TranslateX="{Binding X}" TranslateY="{Binding Y}"/>
                    </Button.RenderTransform>

                </Button>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

</Grid>

视图模型

Public Class myviewmodel
Implements INotifyPropertyChanged
Private Sub NotifyPropertyChanged(Optional propertyName As String = "")
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub

Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private _myrectangles As New ObservableCollection(Of RectItem)
Public Property myrectangles As ObservableCollection(Of RectItem)
    Get
        Return _myrectangles
    End Get
    Set(value As ObservableCollection(Of RectItem))
        _myrectangles = value
        NotifyPropertyChanged()
    End Set
End Property

Public Sub New()
    Dim newrect As New RectItem
    newrect.Height = 100
    newrect.Width = 150
    newrect.X = 50
    newrect.Y = 50
    _myrectangles.Add(newrect)
End Sub

Public Sub PointerDrag(sender As Object, e As ManipulationDeltaRoutedEventArgs)
    Dim dx_point = e.Delta.Translation.X
    NotifyPropertyChanged()
    Dim dy_point = e.Delta.Translation.Y
    NotifyPropertyChanged()
    Dim rec = TryCast(e.OriginalSource, Button)
    Dim selrecitem = TryCast(rec.DataContext, RectItem)

    selrecitem.X += dx_point
    selrecitem.Y += dy_point
End Sub
End Class

RectItemClass

Public Class RectItem
Implements INotifyPropertyChanged
Private Sub NotifyPropertyChanged(Optional propertyName As String = "")
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub

Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

Public Property X As Double
    Get
        Return m_X
    End Get
    Set
        m_X = Value
        NotifyPropertyChanged()
    End Set
End Property
Private m_X As Double
Public Property Y As Double
    Get
        Return m_Y
    End Get
    Set
        m_Y = Value
        NotifyPropertyChanged()
    End Set
End Property
Private m_Y As Double
Public Property Width As Double
    Get
        Return m_Width
    End Get
    Set
        m_Width = Value
        NotifyPropertyChanged()
    End Set
End Property
Private m_Width As Double
Public Property Height As Double
    Get
        Return m_Height
    End Get
    Set
        m_Height = Value
        NotifyPropertyChanged()
    End Set
End Property
Private m_Height As Double
End Class

编辑#1我使用ListView / Listbox而不是使用项目控件,并将所选项目绑定到我的vewimodel中的属性。使用列表视图会有一些问题,让项目展示者与其呈现的项目对齐,并且使用列表框,指针启动事件不会触发。

<ListView x:Name="itemsControl" Grid.Column="1" Grid.Row="1" ItemsSource="{Binding myrectangles, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Background="#FFF2F2F2"  SelectedItem="{Binding selectedrec, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">

        <Interactivity:Interaction.Behaviors>
            <Core:EventTriggerBehavior EventName="ManipulationDelta">
                <Core:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="PointerDrag"/>
            </Core:EventTriggerBehavior>
            <Core:EventTriggerBehavior EventName="PointerPressed">
                <Core:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="PointerPressed"/>
            </Core:EventTriggerBehavior>
            <!--<Core:EventTriggerBehavior EventName="PointerReleased">
                <Core:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="Up"/>
            </Core:EventTriggerBehavior>-->
        </Interactivity:Interaction.Behaviors>



        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Background="White">

                </Canvas>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
       <!--<ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">

                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <ContentPresenter/>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>


            </Style>
        </ListView.ItemContainerStyle>-->
        <ListView.ItemTemplate>

            <DataTemplate>
                <Rectangle x:Name="PageItem" Width="{Binding Width}" Height="{Binding Height}"  Fill="Transparent" Stroke="DodgerBlue" ManipulationMode="TranslateX, TranslateY" IsHitTestVisible="{Binding IsChecked, ElementName=SelectToolButton, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" >


                    <Rectangle.RenderTransform>
                        <CompositeTransform TranslateX="{Binding X}" TranslateY="{Binding Y}"/>
                    </Rectangle.RenderTransform>

                </Rectangle>

            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

</Grid>  

更新了ViewModel

 Public _selectedrec As New RectItem
 Public Property selectedrec As RectItem
    Get
        Return _selectedrec
    End Get
    Set(value As RectItem)
        _selectedrec = value
        NotifyPropertyChanged()
    End Set
End Property

 Public Sub PointerDrag(sender As Object, e As ManipulationDeltaRoutedEventArgs)

    Dim dx_point = e.Delta.Translation.X
    NotifyPropertyChanged()
    Dim dy_point = e.Delta.Translation.Y
    NotifyPropertyChanged()


    selectedrec.X += dx_point
    NotifyPropertyChanged()
    selectedrec.Y += dy_point
    NotifyPropertyChanged()



End Sub

问题示例

没有itemcontainerstyle - 尝试将对象捕捉拖动到画布0,0时

enter image description here

MyHalfFix - 取消注释ItemContainerStyle - 一切正常运行

enter image description here

在实际计划中实施的整体问题

enter image description here

红色项目是listviewitem主持人。它被正确绘制但是定位没有与绘制的矩形对齐,它总是捕捉到画布的0,0点。我可以使它透明,但你也可以看到绘制矩形时它没有正确地跟随光标

1 个答案:

答案 0 :(得分:0)

您可以使用InvokeCommandAction ManipulationDelta事件来避免破坏MVVM模式。 InvokeCommandAction可以将参数传递给viewmodel,我们可以通过参数传递selecteditemManipulationDelta的对象应该是按钮而不是ItemsControlInvokeCommandAction将起作用,实际拖动的是按钮本身。更新后的代码如下:

XAML

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Name="root">
  ...
       <ItemsControl.ItemTemplate>
           <DataTemplate>
               <Button x:Name="PageItem" Background="Transparent" BorderBrush="DodgerBlue" Width="{Binding Width}" Height="{Binding Height}" ManipulationMode="TranslateX, TranslateY" IsHitTestVisible="{Binding IsChecked, ElementName=SelectToolButton, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" >
                   <Interactivity:Interaction.Behaviors>
                       <Core:EventTriggerBehavior EventName="ManipulationDelta" SourceObject="{Binding ElementName=PageItem}">
                           <Core:InvokeCommandAction Command="{Binding DataContext.SendMyDC, ElementName=root}" CommandParameter="{Binding}"></Core:InvokeCommandAction>
                           <Core:CallMethodAction TargetObject="{Binding DataContext, ElementName=root, Mode=OneWay}" MethodName="PointerDrag" />
                       </Core:EventTriggerBehavior>
                   </Interactivity:Interaction.Behaviors>
                   <Button.RenderTransform>
                       <CompositeTransform TranslateX="{Binding X}" TranslateY="{Binding Y}"/>
                   </Button.RenderTransform>
               </Button>
           </DataTemplate>
       </ItemsControl.ItemTemplate>
   </ItemsControl>
</Grid>

myviewmodel

Public Class myviewmodel  
...
Private m_sendCommand As IDelegateCommand
Public Property SendMyDC As IDelegateCommand
    Get
        Return m_sendCommand
    End Get
    Protected Set(value As IDelegateCommand)
        m_sendCommand = value
    End Set
End Property

Public Sub New()
    Me.SendMyDC = New DelegateCommand(AddressOf ExecuteSendMyDC)
    Dim newrect As New RectItem
    newrect.Height = 100
    newrect.Width = 150
    newrect.X = 50
    newrect.Y = 50
    _myrectangles.Add(newrect)
End Sub

Dim selrecitem As RectItem
Public Sub PointerDrag(sender As Object, e As ManipulationDeltaRoutedEventArgs)
    Dim dx_point = e.Delta.Translation.X
    NotifyPropertyChanged()
    Dim dy_point = e.Delta.Translation.Y
    NotifyPropertyChanged()
    'Dim rec = TryCast(e.OriginalSource, Button)
    'Dim selrecitem = TryCast(rec.DataContext, RectItem)
    If selrecitem IsNot Nothing Then
        selrecitem.X += dx_point
        selrecitem.Y += dy_point
    End If
End Sub

Private Sub ExecuteSendMyDC(param As Object)
    selrecitem = CType(param, RectItem)
End Sub 
End Class

DelegateCommand类

Public Class DelegateCommand
Implements IDelegateCommand
Private _execute As Action(Of Object)
Private _canExecute As Func(Of Object, Boolean)
#Region "Constructors"
Public Sub New(execute As Action(Of Object), canExecute As Func(Of Object, Boolean))
    Me._execute = execute
    Me._canExecute = canExecute
End Sub
Public Sub New(execute As Action(Of Object))
    Me._execute = execute
    Me._canExecute = AddressOf Me.AlwaysCanExecute
End Sub
#End Region
#Region "IDelegateCommand"
Private Function AlwaysCanExecute(param As Object) As Boolean
    Return True
End Function
Public Function CanExecute(parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
    Return _canExecute(parameter)
End Function
Public Event CanExecuteChanged(sender As Object, e As EventArgs) Implements System.Windows.Input.ICommand.CanExecuteChanged
Public Sub Execute(parameter As Object) Implements System.Windows.Input.ICommand.Execute
    _execute(parameter)
End Sub

Public Sub RaiseCanExecuteChanged() Implements IDelegateCommand.RaiseCanExecuteChanged
    RaiseEvent CanExecuteChanged(Me, EventArgs.Empty)
End Sub
#End Region
End Class
Public Interface IDelegateCommand
    Inherits ICommand
    Sub RaiseCanExecuteChanged()
End Interface

DelegateCommand是进一步调用其他命令的通用类。更多详情请参阅Command binding inside DataTemplate