以某种方式通知转换器集合已更改

时间:2014-02-20 14:18:58

标签: c# wpf xaml mvvm

此转换器是我的间接问题,或者特别是其中的ObservableCollection user_modules。此转换器连接到一组按钮。

当我的应用程序启动时,集合为空,所有按钮都被禁用,然后在用户登录时填充它。但是,视图和视图模型不会通知集合已更改,按钮在不应该被禁用时保持禁用状态。我该怎么做?

我相信以下三段代码都没问题,但我不确定第四段,我相信这是我需要做的改动。

public class IsEnabledMultiValueConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        try
        {
            bool userHasAccess = false;
            int Module_ID = (int)values[0];
            ObservableCollection<UserModuleLevel> user_module_levels = values[1] as ObservableCollection<UserModuleLevel>;
            UserModuleLevel userModuleLevel = user_module_levels.SingleOrDefault(um => um.Module_ID == Module_ID);

            if (userModuleLevel != null)
            {
                userHasAccess = true;
            }

            return (userHasAccess);
        }
        catch
        {
            return false;
        }
    }

我的XAML:

<Button.IsEnabled>
    <MultiBinding Converter="{StaticResource converter}" >
       <Binding Path="Module_ID" />
       <Binding Path="DataContext.UserModuleCollection"
                RelativeSource="{RelativeSource AncestorType=Window}" />
    </MultiBinding>
</Button.IsEnabled>

我的ViewModel:一旦用户登录UserModuleLevels,就会填充_current_user。

public ObservableCollection<UserModuleLevel> UserModuleCollection
{
    get { return CurrentUser._current_user.UserModuleLevels; }
}

保存集合的用户类:

public class User
{
    public User(){}

    public int User_ID { get; set; }
    public string Name { get; set; }
    public ObservableCollection<UserModuleLevel> UserModuleLevels = new ObservableCollection<UserModuleLevel>();
}

3 个答案:

答案 0 :(得分:1)

我不确定你要在这里实现什么,但我能得到的是你想要在列表中添加或删除项目时调用转换器

如果是这种情况,你可以在MultiBinding下的XAML中有另一个绑定,它将绑定到ObservableCollection的Count 。每当添加/删除项目时,Count都会更新。所以,你可以这样做只是为了得到通知。

<Button.IsEnabled>
    <MultiBinding Converter="{StaticResource converter}" >
       <Binding Path="Module_ID" />
       <Binding Path="DataContext.UserModuleCollection"
                RelativeSource="{RelativeSource AncestorType=Window}" />
       <Binding Path="DataContext.UserModuleCollection.Count" <-- Only to refresh
                RelativeSource="{RelativeSource AncestorType=Window}" />
    </MultiBinding>
</Button.IsEnabled>

答案 1 :(得分:0)

填充observable集合时,不会执行转换器的Convert方法。这是因为只有ListBoxComboBox之类的ItemsControl会监听CollectionChanged接口的INotifyCollectionChanged事件。但这不适用于你的问题。

如果我正确理解您的代码,我建议您创建一个为每个按钮实例化的新ViewModel类。在其中,您可以指定模块ID以及用户是否可以使用它(您当前在转换器中执行的检查)。将每个按钮绑定到该视图模型的新实例。

我希望这会有所帮助。如果您有任何疑问,请发表评论。

答案 2 :(得分:0)

可能的原因有两点突出。你说当用户登录模块级别时会填充? 那么最初的CurrentUser和后续模块级别将为null? 在设置Currentuser及其UserModuleLevels时,您可能需要引发通知事件。

此外,在第四部分中,您将私有变量设置为新变量,但该属性也有一个setter,没有通知事件。如果您随后设置该属性,则需要实现INotifyPropertyChanged。或者通过删除setter使其成为只读。

     public class User:INotifyPropertyChanged
        {
            public User(){}

            public int User_ID { get; set; }
            public string Name { get; set; }
            private ObservableCollection<UserModuleLevel> user_module_levels = new ObservableCollection<UserModuleLevel>();

            public ObservableCollection<UserModuleLevel> UserModuleLevels
            {
                get
                { return user_module_levels; }
                set
                { 
                  user_module_levels = value; 
                  this.OnPropertyChanged();
                }
            }

        public event PropertyChangedEventHandler PropertyChanged;

                [NotifyPropertyChangedInvocator]
                protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
                {
                    PropertyChangedEventHandler handler = PropertyChanged;
                    if (handler != null)
                    {
                        handler(this, new PropertyChangedEventArgs(propertyName));
                    }
                }

        }