WPF MVVM - 监视对绑定对象的更改(例如,如果IsDirty,则启用保存)

时间:2015-04-08 17:20:23

标签: wpf mvvm

在WPF中,使用MVVM模式(并使用MVVMLight工具包),我有一个用户控件,显示产品的可编辑字段。此UC绑定到列出所有产品的ComboBox中的选定值。

这一切都很好,但在我的Product类中,我有一个名为IsDirty的布尔字段,当更新产品上的任何属性时,该字段设置为true。 我希望只要所选产品的IsDirty属性为true(在用户控件中),就会启用主视图中的保存按钮。我无法弄清楚如何使用IsSaveEnabled属性“观察“SelectedProduct中的变化(基本上当它变脏)。

我能够通过使用事件处理程序来完成此操作,但是将事件附加到所选的每个产品上,它看起来很脏而且很笨重。这是关于如何正确观察对绑定对象的更改的遗漏吗?

Products.xaml (部分)

<Grid DataContext="{Binding Source={StaticResource ProductsViewModel}}">
    <StackPanel>
        <ComboBox x:Name="ProductsComboBox" 
                  ItemsSource="{Binding Path=ProductList}" 
                  DisplayMemberPath="Name" 
                  SelectedItem="{Binding SelectedProduct}" />
        <uc:Product DataContext="{Binding SelectedItem, ElementName=ProductsComboBox}" />
        <Button Content="Save" IsEnabled="{Binding IsSaveEnabled}" Click="Button_Click" />
    </StackPanel>
</Grid>

ProductsViewModel.cs (部分)

public bool IsSaveEnabled
{
    get { return SelectedProduct.IsDirty; }
}

public ProductViewModel SelectedProduct
{
    get { return _selectedProduct; }
    set { 
        // I can use the next line, but it seems really clunky and creates a ton of event listeners
        // value.PropertyChanged += SelectedProduct_PropertyChanged;
        Set(() => SelectedProduct, ref _selectedProduct, value); 
        }
}

// This is the event handler that seems bad form and a duplication of functionality that is already in the Product class
//void SelectedProduct_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
//    {
//        SelectedProperty.IsDirty = true;
//        RaisePropertyChanged(() => IsSaveEnabled);
//    }

2 个答案:

答案 0 :(得分:1)

我会这样做:

public class ProductsViewModel
{
    private bool _isSaveEnabled;

    public bool IsSaveEnabled
    {
        get { return _isSaveEnabled; }
        private set
        {
            _isSaveEnabled = value;
            RaisePropertyChanged();
        }
    }

    public ProductViewModel SelectedProduct
    {
        get { return _selectedProduct; }
        set 
        { 
            if (value != _selectedProduct)
            {
                // unsubscribe from old selected product changes
                //
                _selectedProduct.PropertyChanged -= OnPropertyChanged;

                // subscribe to new selected product changes
                //
                value.PropertyChanged += OnPropertyChanged;

                _selectedProduct = value;
                RaisePropertyChanged();
            }
        }
    }

    private void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        SelectedProperty.IsDirty = true;
        IsSaveEnabled = SelectedProperty.IsDirty;
    }   
}

您看到这么多事件处理程序的原因是因为您每次选择产品更改时都要订阅新的事件处理程序。你只想做一个,所以在订阅新的之前一定要取消订阅旧的。此外,不需要为IsSaveEnabled执行RaisePropertyChanged,只需在其setter中引发事件。

答案 1 :(得分:1)

您可能应该使用命令:

    public static RoutedCommand Command_Save = new RoutedCommand ( );

    void Command_Save_Executed ( object sender, ExecutedRoutedEventArgs e )
    {
         // save the product
    }

    void Command_Save_CanExecute ( object sender, CanExecuteRoutedEventArgs e )
    {
        e.CanExecute = SelectedProduct.IsDirty;
    }

XAML:

<Button Content="Save" Command="{x:Static MY:ProductsControl.Command_Save }" />

并将其绑定到控件(在ctor或xaml中):

            this.CommandBindings.Add( new CommandBinding( Command_SaveAs,
                                                      Command_SaveAs_Executed,
                                                      Command_SaveAs_CanExecute ) );

命令基础结构将调用CanExecute事件处理程序来禁用/启用按钮。