locked
[UWP] How to Execute button command in another controls datacontext RRS feed

  • Question

  • I have a bound listview populated with items.

    I have a button that executes a command to add an item to the list.

    I am now trying to add a button on each item to remove itself from the listview.

    I need to have the remove event in the same class as the add event, From what I read I can achieve this by specifying the ElementName and pass the item to be remove via the CommandParameter.

    However I am not receiving remove events, where am I going wrong? Is there a simpler way?

    I am using commands because the xml is inside a DataTemplate.

    <ListView Name="AliasValuesList" ItemsSource="{Binding AliasValues, Mode=TwoWay}" Margin="0,0,0,0" IsItemClickEnabled="True" Grid.Row="12" Grid.Column="0" Grid.ColumnSpan="2">
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <Grid Padding="0,0,0,0">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition Height="Auto"/>
                                    </Grid.RowDefinitions>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="300"/>
                                        <ColumnDefinition Width="40"/>
                                    </Grid.ColumnDefinitions>
                                    <TextBox Text="{Binding MyAliasValue, Mode=TwoWay}" Grid.Row="0" Grid.Column="0" />
                                    <Button Name="RemoveAlias" Content="Remove" Grid.Row="0" Grid.Column="1" Command="{Binding Path=AddAliasCommand, ElementName=AddAlias}" CommandParameter="{Binding}"/>
                                </Grid>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                    <Button x:Name="AddAlias" Content="Add Alias" Grid.Row="13" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" Command="{Binding Path=AddAliasCommand}"/>

    Saturday, June 24, 2017 1:30 AM

Answers

  • Let's make it simple than complex. Firstly, you need to figure out the data context for your deleting command. Usually, it would be your root element on the xaml, a Page or Window or UserControl. And your StackPanel should share the data context. Try this,

    1. Give a name to your StackPanel like this:

    <Window balabala>
      <StackPanel x:Name="ContextHolder">

          <ListView .. >

                 <!-- Your delete button here... -->

          </ListView>

          <Button x:Name="AddAlias" />

      </StackPanel>

    </Window>

    2. Update your binding expression for Deleting button:

    {Binding Path=DataContext.AddAliasCommand, ElementName=ContextHolder, xxxxxparamxxxxx}

    // I noticed you are trying to bind delete button to AddAliasCommand, I guess you are doing it intentionally just to verify the command is triggered.

    3. If this triggers the command, which I think it should, try moving the element name to upper level. If this doesn't work, please post the whole xaml file.
    • Edited by Saar Shen Friday, July 7, 2017 11:32 PM
    • Marked as answer by Sav Man Saturday, July 8, 2017 7:07 AM
    Friday, July 7, 2017 11:30 PM

All replies

  • Hi Sav Man,

    If you want to add or delete an item in the ListView, you can do it more easily by using the ObservableCollection<T> class as the data collection object which should be bound to your ListView, because it has implemented the INotifyPropertyChanged interface. When you delete item from itemsource, it would update UI automatically. So you just need to operate the ObservableCollection object by adding or removing an item object. 

    On other hand, you maybe need to use the SelectedItem property of ListView, you would get the current SelectedItem, then you could delete it from your itemsource in your button click event.

    Best regards,

    Breeze


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, June 26, 2017 7:41 AM
  • Yes, AliasValues in my sample is an ObservableCollection<T> exactly as you suggest. The problem is MyAliasValue is a property of object T and because the DataContext gets overridden with object T the remove button command is sent to object T which has no knowledge of the ObservableCollection<T> so I cant call remove from it.

    This is why I am trying to bind the remove buttons back to the AddAlias Element so the event goes to ObservableCollection<T> that way I can actually call remove to remove the item clicked as specified by the CommandParameter. Thats the theory anyway but its not working.

    Yes, I could use a multiselect ListView and use the SelectedItem property to determine what to remove but that is a different interface to what I am looking for.


    • Edited by Sav Man Monday, June 26, 2017 10:34 AM
    Monday, June 26, 2017 10:33 AM
  • Hello Sav Man,

    In order to look into this issue more accurately, could you give me a simple reproduce sample? It is hard to say if there is no enough code to reproduce it.

    Best regards,

    Breeze


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, June 27, 2017 6:53 AM
  • Not sure why you need the code but its something like this:

    Public Class MyClass1
        Public Property AliasValues As ObservableCollection(Of MyClass2)
        Public Property AddAliasCommand As MyAddAliasCommand
    
        Sub New()
            AliasValues = New ObservableCollection(Of MyClass2)
    	AddAliasCommand = New MyAddAliasCommand
        End Sub
    End Class
    
    Public Class MyAddAliasCommand
        Implements ICommand
    
        Private Function ICommand_CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
            Return True
        End Function
    
        Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
    
        Private Sub ICommand_Execute(parameter As Object) Implements ICommand.Execute
            Dim NewMyClass2 = New MyClass2
            NewMyClass2.MyAliasValue = "New Alias"
            AliasValues.Add(NewMyClass2)
        End Sub
    End Class
    
    
    Public Class MyClass2
        Inherits DependencyObject
        Implements INotifyPropertyChanged
    
        Public Shared ReadOnly MyAliasValueProperty As DependencyProperty = DependencyProperty.Register("MyAliasValue", GetType(String), GetType(MyClass2), New PropertyMetadata(Nothing))
    
        Public Property MyAliasValue As String
            Set(value As String)
                Me.SetValue(MyAliasValueProperty, value)
            End Set
            Get
                Return Me.GetValue(MyAliasValueProperty)
            End Get
        End Property
    
    End Class

    Note: I havent bothered creating a remove command, If I can get the add command to execute from the remove buttons I will be away.

    Also Note: my XAML doesn't show that it's in a DataTemplate would that be causing issues?


    • Edited by Sav Man Wednesday, June 28, 2017 7:35 AM
    Wednesday, June 28, 2017 7:31 AM
  • Hello Sav Man,

    Sorry for being later, I have created a simple sample and it should satisfy your requirement, you can have a try with the following code.

    The MainPage.xaml,

     <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <ListView Name="AliasValuesList" ItemsSource="{Binding AliasValues, Mode=TwoWay}" Margin="0,0,0,0" IsItemClickEnabled="True">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <Grid Padding="0,0,0,0">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="300"/>
                                <ColumnDefinition Width="100"/>
                            </Grid.ColumnDefinitions>
                            <TextBox Text="{Binding MyAliasValue, Mode=TwoWay}" Grid.Row="0" Grid.Column="0" />
                            <Button Name="RemoveAlias" Tag="{Binding Id}" Content="Remove" Grid.Row="0" Grid.Column="1" Command="{Binding Path=AddAliasCommand}" CommandParameter="{Binding ElementName=RemoveAlias}"/>
                        </Grid>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            <Button x:Name="AddAlias" Content="Add Alias" Grid.Row="13" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" Command="{Binding Path=AddAliasCommand}" CommandParameter="{Binding ElementName=AddAlias}"/>
        </StackPanel>

    The MainPage.xaml.vb,

    Public NotInheritable Class MainPage
        Inherits Page
    
        Public Sub New()
            Me.InitializeComponent()
            Dim class1 = New MyClass1()
            AliasValues = class1.AliasValues
            AddAliasCommand = class1.AddAliasCommand
            Me.DataContext = Me
        End Sub
        Public Property AddAliasCommand() As MyAddAliasCommand
            Get
                Return m_AddAliasCommand
            End Get
            Set
                m_AddAliasCommand = Value
            End Set
        End Property
        Private m_AddAliasCommand As MyAddAliasCommand
        Public Property AliasValues() As ObservableCollection(Of MyClass2)
            Get
                Return m_AliasValues
            End Get
            Set
                m_AliasValues = Value
            End Set
        End Property
        Private m_AliasValues As ObservableCollection(Of MyClass2)
    
    End Class
    
    
    Public Class MyClass1
        Public Property AliasValues() As ObservableCollection(Of MyClass2)
            Get
                Return m_AliasValues
            End Get
            Set
                m_AliasValues = Value
            End Set
        End Property
        Private m_AliasValues As ObservableCollection(Of MyClass2)
        Public Property AddAliasCommand() As MyAddAliasCommand
            Get
                Return m_AddAliasCommand
            End Get
            Set
                m_AddAliasCommand = Value
            End Set
        End Property
        Private m_AddAliasCommand As MyAddAliasCommand
    
        Public Sub New()
            Dim a As String
            Dim myclassg As New MyClass2()
    
            myclassg.MyAliasValue = "Hello first1"
    
    
            AliasValues = New ObservableCollection(Of MyClass2)()
            AddAliasCommand = New MyAddAliasCommand(Function(s)
                                                        Me.MyMethod(TryCast(s, Button))
    
                                                    End Function, True)
            AliasValues.Add(New MyClass2() With {
                .MyAliasValue = "Hello first1",
                .AddAliasCommand = Me.AddAliasCommand,
                .Id = 0
            })
            AliasValues.Add(New MyClass2() With {
                .MyAliasValue = "Hello first2",
                .AddAliasCommand = Me.AddAliasCommand,
                .Id = 1
            })
            AliasValues.Add(New MyClass2() With {
                .MyAliasValue = "Hello first3",
                .AddAliasCommand = Me.AddAliasCommand,
                .Id = 2
            })
            AliasValues.Add(New MyClass2() With {
                .MyAliasValue = "Hello first4",
                .AddAliasCommand = Me.AddAliasCommand,
                .Id = 3
            })
            AliasValues.Add(New MyClass2() With {
                .MyAliasValue = "Hello first5",
                .AddAliasCommand = Me.AddAliasCommand,
                .Id = 4
            })
        End Sub
    
        Public Sub MyMethod(param As Button)
            If param.Name = "AddAlias" Then
                Dim num As Integer = AliasValues.Count
                AliasValues.Add(New MyClass2() With {
                    .MyAliasValue = "Hello first",
                    .AddAliasCommand = Me.AddAliasCommand,
                    .Id = num
                })
            Else
                AliasValues.RemoveAt(CInt(param.Tag))
            End If
    
        End Sub
    End Class
    
    
    Public Class MyClass2
        Inherits DependencyObject
        Implements INotifyPropertyChanged
        Public Shared ReadOnly MyAliasValueProperty As DependencyProperty = DependencyProperty.Register("MyAliasValue", GetType(String), GetType(MyClass2), New PropertyMetadata(Nothing))
        Public Property MyAliasValue() As String
            Get
                Return DirectCast(GetValue(MyAliasValueProperty), String)
            End Get
            Set
                Me.SetValue(MyAliasValueProperty, Value)
            End Set
        End Property
    
        Private Event INotifyPropertyChanged_PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    
        Public Property AddAliasCommand() As ICommand
            Get
                Return m_AddAliasCommand
            End Get
            Set
                m_AddAliasCommand = Value
            End Set
        End Property
        Private m_AddAliasCommand As ICommand
        Public Property Id() As Integer
            Get
                Return m_Id
            End Get
            Set
                m_Id = Value
            End Set
        End Property
        Private m_Id As Integer
    End Class
    
    
    
    Public Class MyAddAliasCommand
        Implements ICommand
        Public Event CanExecuteChanged As EventHandler
        Private Event ICommand_CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
        Private _action As Action(Of Object)
        Private _canExecute As Boolean
    
        Public Sub New(action As Action(Of Object), canExecute As Boolean)
            _action = action
            _canExecute = canExecute
        End Sub
        Public Sub Execute(parameter As Object)
            _action(parameter)
        End Sub
    
        Private Function ICommand_CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
            Return _canExecute
        End Function
    
        Private Sub ICommand_Execute(parameter As Object) Implements ICommand.Execute
            _action(parameter)
        End Sub
    End Class

    I can add and remove the item by clicking the AddAlias and RemoveAlias Button.(Please be attention to the remove method, it is just for test remove an item, you should change to make it no issue when remove item).

    Best regard,

    Breeze


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Proposed as answer by Xavier Xie-MSFT Thursday, July 6, 2017 8:13 AM
    • Unproposed as answer by Sav Man Thursday, July 6, 2017 9:38 AM
    • Edited by Breeze Liu Friday, July 7, 2017 2:41 AM
    Friday, June 30, 2017 6:15 AM
  • Hi Breeze, Thanks for the effort!

    I see you have an AddAliasCommand in both Class1 and Class2, The purpose in my question was to remove this requirement as I do not believe it should be necessary. I'm sure you would agree this simple problem causes alot of code bloat.

    I drew this diagram to better show what I am ultimately looking for, I am making an assumption this is actually possible.

    I have highlighted the problem.


    There must be a better way?...
    • Edited by Sav Man Friday, June 30, 2017 7:47 AM
    Friday, June 30, 2017 7:45 AM
  • Hello Sav Man,

    After many attempt and test, if I do as the logical of above diagram, it should have much code bloat. I think you have made the project more complex than it should, you can give a Button click event or binding a command on the page behind code directly, then write other logic or code on the Model / ViewModel, it should be more clear.

    Best regards,

    Breeze


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, July 5, 2017 2:23 AM
  • Hi Breeze,

    I've got it down to an 8 line helper function and a 1 line event/command

    But the event is still where I don't want it.

    What about reletive source binding?

    Wednesday, July 5, 2017 6:17 AM
  • Hi Sav Man,

    The RelativeSource provides a means to specify the source of a binding in terms of a relative relationship in the run-time object graph, You can have a try with the relative source binding. But I think the simplest way is to handle it directly on the page code behind.

    Best regards,

    Breeze


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, July 5, 2017 7:24 AM
  • Is it the equivelant of using VisualTreeHelper.GetChild(). That is what I am using to find the parent datacontext from my button click event. Does that mean I can Bind my button click to my ParentClass?

    Sounds like what I am after but I have not managed to get it to work.

    Wednesday, July 5, 2017 8:20 AM
  • Hi Sav Man,

    Thanks for your reply.

    I’m not sure if you have strayed from your original question. Your original question was “what I read I can achieve this by specifying the ElementName and pass the item to be remove via the CommandParameter. However I am not receiving remove events, where am I going wrong? Is there a simpler way?”.

    I saw that Breeze has provided a simple code sample to solve this issue. I’ve checked his code and it would be able to achieve your original target.

    But you said “There must be a better way”. It’s hard to say. Maybe, there’s a better way. If you’re still going on finding a better way. You could change the type of your thread to discussion. Then more community members might give you some information.

    >>”Is it the equivelant of using VisualTreeHelper.GetChild(). That is what I am using to find the parent datacontext from my button click event. Does that mean I can Bind my button click to my ParentClass?”

    About this question, I really suggested that you could open a new thread and post a simple reproducible code sample. It’s because your question has been changed from “not receiving remove events” to “find the parent datacontext from my button click event.”. 

    Maybe, you would say they’re the same questions, but Breeze has provided a code sample to help you solve your original question, you just didn’t accept his solution. Then, you’re finding another way. That’ why I suggest you to open a new thread.

    Thanks for your understanding.

    Best Regards,

    Xavier Eoro


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, July 6, 2017 8:12 AM
  • Hi Xavier and Breeze,

    Thanks for helping

    My original question was "How to Execute button command in another controls datacontext" this is still unresolved. You seem to have my question confused with one of my attempts to solve the problem. I backed up my question by stating "I need to have the remove event in the same class as the add event".

    I had no clarification on if I was on the right path using ElementName as I was trying in my original sample provided. I since learnt from Breeze's comment and my current workaround that RalativeSource may be the better approach however I have attemped it before with no success, probably doing something simple wrong.

    Sorry but I come accross this same problem on every project and my best solution seems to go against what I know about MVVM(I'm no expert) as a result adds bloat to my modal. Given UWP XAML binding capabilities it surprises me that what seems to me to be such a simple problem requires such a complicated solution. My gut tells me there is a simple solution, this is why I am trying to consult the experts.

    If there is no solution please let me know and I will put it to bed and stick with my current workaround. It just bugs me that I have to put an event in a object that has absolutely nothing to do with the object itself just to achieve my desired user interface.

    Sorry I wasn't aware of Discussions, I will consider that next time

    Thanks







    • Edited by Sav Man Thursday, July 6, 2017 10:02 AM
    Thursday, July 6, 2017 9:32 AM
  • Hello Sav Man,

    >> I backed up my question by stating "I need to have the remove event in the same class as the add event".

    I tried to implement the remove event in the same class as the add event. As your above diagram, if I put the both method in the ParentClass and the ICommand in the child class, I can not refer the the Add and remove method. If I make them be shared method in parent class, I can not change the ObservableCollection item in the Parent class. If I make the both method in the child class, I can not modify the ObservableCollection in the Parent class too. The question will become more complex than my first solution. So I recommend to write the logic to remove the Item in the page code behind, it should be more clear. The RalativeSource still can not do any work with this issue in my attempt.

    Best regards,

    Breeze


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Edited by Breeze Liu Friday, July 7, 2017 2:55 AM
    Friday, July 7, 2017 2:39 AM
  • Hi Sav,

    The following line you provided doesn't bind to the proper data context for your command:

    <Button Name="RemoveAlias" Content="Remove" Grid.Row="0" Grid.Column="1" Command="{Binding Path=AddAliasCommand, ElementName=AddAlias}" CommandParameter="{Binding}"/>

    Specifically, {Binding ElementName=AddAlias, Path=AddAliasCommand} will bind to the element named 'AddAlias', which is your AddAliasButton, then it follow the path 'AddAliasCommand'. Since your AddAlias button doesn't have a ICommand property named AddAliasCommand, the you will binding to Null. I think that's why you are not seeing the command being triggered.

    Friday, July 7, 2017 4:21 AM
  • Thanks Saar, That makes perfect sense!

    I just came accross a good diagram on RelativeSource, appears to show exacly what I'm after:

    https://stackoverflow.com/questions/84278/how-do-i-use-wpf-bindings-with-relativesource

    Does RelativeSource PreviousData do exactly as I am after(Get the parent datacontext), the documentation is not very clear?

    Does RelativeSource FindAncestor, AncestorType={x:Type ListView} work, from memory x:Type was not supported in UWP?...

    Actually are any of those modes supported in UWP?

    Not tested yet but would this work?:

    <ListView Name="AliasValuesList" ItemsSource="{Binding AliasValues, Mode=TwoWay}" Margin="0,0,0,0" IsItemClickEnabled="True" Grid.Row="12" Grid.Column="0" Grid.ColumnSpan="2"> <ListView.ItemTemplate> <DataTemplate> <Grid Padding="0,0,0,0"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="300"/> <ColumnDefinition Width="40"/> </Grid.ColumnDefinitions> <TextBox Text="{Binding MyAliasValue, Mode=TwoWay}" Grid.Row="0" Grid.Column="0" /> <Button Name="RemoveAlias" Content="Remove" Grid.Row="0" Grid.Column="1" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}} Path=DataContext.AddAliasCommand}" CommandParameter="{Binding}"/>

    <Button Name="RemoveAlias" Content="Remove" Grid.Row="0" Grid.Column="1" Command="{Binding RelativeSource={RelativeSource PreviousData} Path=AddAliasCommand}" CommandParameter="{Binding}"/>
    </Grid> </DataTemplate> </ListView.ItemTemplate> </ListView> <Button x:Name="AddAlias" Content="Add Alias" Grid.Row="13" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" Command="{Binding Path=AddAliasCommand}"/>

    Breeze, are these the issues you came up against?


    • Edited by Sav Man Friday, July 7, 2017 7:57 AM
    Friday, July 7, 2017 7:56 AM
  • Let's make it simple than complex. Firstly, you need to figure out the data context for your deleting command. Usually, it would be your root element on the xaml, a Page or Window or UserControl. And your StackPanel should share the data context. Try this,

    1. Give a name to your StackPanel like this:

    <Window balabala>
      <StackPanel x:Name="ContextHolder">

          <ListView .. >

                 <!-- Your delete button here... -->

          </ListView>

          <Button x:Name="AddAlias" />

      </StackPanel>

    </Window>

    2. Update your binding expression for Deleting button:

    {Binding Path=DataContext.AddAliasCommand, ElementName=ContextHolder, xxxxxparamxxxxx}

    // I noticed you are trying to bind delete button to AddAliasCommand, I guess you are doing it intentionally just to verify the command is triggered.

    3. If this triggers the command, which I think it should, try moving the element name to upper level. If this doesn't work, please post the whole xaml file.
    • Edited by Saar Shen Friday, July 7, 2017 11:32 PM
    • Marked as answer by Sav Man Saturday, July 8, 2017 7:07 AM
    Friday, July 7, 2017 11:30 PM
  • Thanks Saar, you are a legend!

    Works awesome, DataContext.AddAliasCommand was all I had overlooked lol, Makes perfect sense, Exactly what I was looking for!

    I new it would be something simple! 

    Only potential problem I can see with this though is what happens if the StackPanel is in a DataTemplate, ElementName rather than looking up the visual tree I'm guessing it will look down from the top, this means it may try to remove it from the wrong ContextHolder.  If you don't mind how would you fix that?

    Thanks again!





    • Edited by Sav Man Saturday, July 8, 2017 7:38 AM
    Saturday, July 8, 2017 7:07 AM
  • Hi Sav,

    Thanks for your comment.

    I've been trying to pull up this page and I finally found it, please refer the commands within collections section:

    https://msdn.microsoft.com/en-us/library/gg405494(v=pandp.40).aspx

    Thanks


    I build UWPs: Arrnage Pro, Cloud Resource Tools

    Sunday, July 9, 2017 5:25 AM