tags:

views:

117

answers:

4

Hi

I'm using MVVM and custom ICommand objects are provided by ViewModel layer. One ViewModel object at the same time can be attached via DataContext property to many View objects (windows, pages, etc). In ICommand.CanExecute() I want to check absence of validation errors for some controls in View (which attached to ViewModel props, significant for a particular VM command). One ViewModel can provide many commands, each of them has own set of controls for errors validation verification. So, pseudo-XAML is:

<Button.CommandParameter>
    <x:Array Type="sys_win:DependencyObject">
        <sys_win:DependencyObject>
            <reference_to_textbox_or_other_control/>
        </sys_win:DependencyObject>
        <sys_win:DependencyObject>
            <reference_to_textbox_or_other_control/>
        </sys_win:DependencyObject>
    </x:Array>
</Button.CommandParameter>

The second problem is that the particular command may be invoked by control, which itself is the part of the DataTemplate for collection item (in my case - part of ListBoxItem data template). My templated listbox item has two text boxes (binded to two props of corresponding ViewModel) and button, which invoke the ViewModel command. So, in command CanExecute() I need to check for validation errors for some window controls & two text boxes, which belongs to this listitem, not other items. The code below works fine if I want to pass ListBoxItem.IsSelected property as CommandParameter:

<Button DataContext="{Binding}" 
        Command="{Binding Path=SwitchCommand}"
        CommandParameter="{Binding Path=IsSelected, RelativeSource={
                                   RelativeSource
                                   Mode=FindAncestor,
                                   AncestorType={x:Type ListBoxItem}}}"/>

But how can I pass whole (DependencyObject)ListBoxItem as the CommandParameter? And how this ListBoxItem, passed via {Binding RelativeSource} can be mixed with other current window controls in the first code example?

A: 

Just use a binding with no Path :

<Button DataContext="{Binding}" 
        Command="{Binding Path=SwitchCommand}"
        CommandParameter="{Binding RelativeSource=
                                   {RelativeSource
                                    Mode=FindAncestor,
                                    AncestorType={x:Type ListBoxItem}}}"/>
Thomas Levesque
Thomas Levesque, thank you. Its working, :)
P A V L I K
A: 

Hi, I'm not sure if I'm reading your example correctly, but it seems to violate a bit of the MVVM principle. (My apologies if I read it incorrectly).

The idea behind MVVM is to decouple the viewmodel from any dependency on a XAML / View entity. You're breaking that by having the CommandParameter dependent on the usercontrol. What I would do is create state properties in the ViewModel and bind the usercontrol validations to those states, then in CanExecute you can test the values of those properties rather than trying to bind to a usercontrol.

Doobi
A: 

Doobi, english isn't my native language, I knew it rather bad than normal, so your partially incorrect understanding of the 1st post is my fault, :)

ViewModel provides commands, which utilizes properties also provided by ViewModel. Properties was bound to View controls & errors validation provided via IDataErrorInfo, which implemetation is the part of ViewModel too.

Despite the fact, that in View all error values marked by special template, user may try to invoke one of ViewModel commands, which uses properties with (currently) error values. In order to block this ability we mast in ICommand.Execute() check all the properties, which values used by this command. So, we check ViewModel properities for errors two times: 1) in string IDataErrorInfo.this[string propertyName] when property value is changed 2) in ICommand.CanExecute when WPF engine update UI

In order to avoid implementation (2) I want to transmit list of View controls (bound to the ViewModel properties, which are significant for current ViewModel command) in ICommand.CanExecute as CommandParameter & check for errors via Validation.GetHasError(DependencyObject). Because Command receves list of DependencyObjects, ViewModel remains independent from View.

But today, after a lot of thinking I concluded that my approach is like the invention of the square wheel & I've refused this idea.

P A V L I K
A: 

I'm very sorry, but how can I add the references to controls in xaml?

<Button.CommandParameter>
    <x:Array Type="sys_win:DependencyObject">
        <sys_win:DependencyObject>
            <reference_to_textbox_or_other_control/>
        </sys_win:DependencyObject>
        <sys_win:DependencyObject>
            <reference_to_textbox_or_other_control/>
        </sys_win:DependencyObject>
    </x:Array>
</Button.CommandParameter>
P A V L I K