使用MVVM从WPF中的ViewModel触发命令

时间:2012-05-02 12:32:52

标签: wpf mvvm user-controls

我创建了一些具有可绑定“ClearCommand”ICommand依赖项属性的自定义控件(NOT UserControls)。此属性将完全按照它的声音执行:它将清除控件中的所有值(文本框等)。我还将(一些)相同的属性绑定到我在下面描述的VM。

现在我一直试图在以下MVVM场景中的那些控件中触发ClearCommand:

我在我的视图中添加了一些这样的控件。视图还包含一个“保存”按钮,该按钮绑定到我的ViewModel的SaveCommand DelegateCommand属性。

我需要做的是,成功保存后,VM应该在视图中找到的那些控件上触发ClearCommandenter image description here

更新

我在下面添加了代码示例。我有一些类似于ExampleCustomControl的控件。此外,请注意,如果它完全关闭,我愿意重组一些。

示例控制片段:

public class ExampleCustomControl : Control {

    public string SearchTextBox { get; set; }
    public IEnumerable<CustomObject> ResultList { get; set; }

    public ExampleCustomControl() {
        ClearCommand = new DelegateCommand(Clear);
    }

    /// <summary>
    /// Dependency Property for Datagrid ItemSource.
    /// </summary>
    public static DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem",
        typeof(CustomObject), typeof(ExampleCustomControl), new PropertyMetadata(default(CustomObject)));

    public CustomObject SelectedItem {
        get { return (CustomObject)GetValue(SelectedCustomObjectProperty); }
        set { SetValue(SelectedCustomObjectProperty, value); }
    }

    public static DependencyProperty ClearCommandProperty = DependencyProperty.Register("ClearCommand", typeof(ICommand),
            typeof(ExampleCustomControl), new PropertyMetadata(default(ICommand)));

    /// <summary>
    /// Dependency Property for resetting the control
    /// </summary>
    [Description("The command that clears the control"), Category("Common Properties")]
    public ICommand ClearCommand {
        get { return (ICommand)GetValue(ClearCommandProperty); }
        set { SetValue(ClearCommandProperty, value); }
    }

    public void Clear(object o) {
        SearchTextBox = string.Empty;
        SelectedItem = null;
        ResultList = null;
    }
}

示例视图片段:

<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="30"/>
    </Grid.RowDefinitions>
    <control:ExampleCustomControl Grid.Row="0"
        SelectedItem="{Binding Selection, UpdateSourceTrigger=PropertyChanged}" />
    <Button Grid.Row="1" x:Name="ResetButton" Command="{Binding SaveCommand}">
        Save
    </Button>
</Grid>

示例ViewModel:

public class TestViewModel : WorkspaceTask {
    public TestViewModel() {
        View = new TestView { Model = this };
        SaveCommand = new DelegateCommand(Save);
    }

    private CustomObject _selection;
    public CustomObject Selection {
        get { return _selection; }
        set {
            _selection = value;
            OnPropertyChanged("Selection");
        }
    }

    public DelegateCommand SaveCommand { get; private set; }
    private void Save(object o) {
        // perform save
        // clear controls
    }
}

3 个答案:

答案 0 :(得分:2)

正如其他人所说,虚拟机不应该直接在MVVM中了解视图,因此虚拟机触发自定义控件上的某些内容以清除所有内容是没有意义的。

我会将自定义控件的DataContext设置为一个对象,该对象具有您要清除的所有属性,这些属性都是绑定(双向)到文本框等。然后在保存( )方法您可以设置一个新对象(自定义控件DataContext绑定到该对象),并且将为您清除所有属性(假设您已在对象上实现了INotifyPropertyChanged)。

更新:

根据我的评论,请参阅当前设置的解决方法示例(未经测试的顺便说一句):

    public static DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem",
        typeof(CustomObject), typeof(ExampleCustomControl), new PropertyMetadata(default(CustomObject), OnSelectedItemChanged));


    private static void OnSelectedItemChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {
        var cont = source as ExampleCustomControl;

            //do all the clearing of txtboxes etc here....
        cont.SearchTextBox = string.Empty;
    }

但是我仍然会尝试将所有这些移动到VM中。即,有一个清晰的命令,就像你使用save命令一样,将文本框文本等绑定到VM中的属性,当命令被调用时,它会清除所有内容,然后你可以从VM中的Save方法轻松调用。但显然我不知道你想要实现的目标是什么,或者selectItem和文本框等是如何相关的,所以我一直在考虑(一如既往)。

答案 1 :(得分:1)

听起来你正在以错误的方式思考这个问题。在MVVM中,ViewModel永远不应该知道有关自定义控件的任何信息(因此您遇到此Clear功能的问题)。

您的要求有点模糊,但您考虑过:

1)如果属性是从VM绑定的,那么Control无法检测到这些属性何时被更改?

2)如果你真的需要从XAML层调用Clear并希望保持纯MVVM,那么请考虑类似Expression Blend SDK的CallMethodAction

答案 2 :(得分:0)

作为我评论的后续内容。我怀疑您的命令是针对视图并直接清除TextBox es。相反,让您的命令以ViewModel为目标并清除View绑定的属性。然后,您可以将命令作为ViewModel上的属性,并在需要时调用它。