【发布时间】:2013-12-04 15:49:19
【问题描述】:
这是使用 C# 和 MVVM。
目前我有一堆按钮通过绑定一个名为 ModuleCollection 的 ObservableCollection
模块定义为:
public string ModuleName { get; private set; }
public string ModuleAbbreviation { get; private set; }
public bool ModuleDisabled { get; private set; }
public DateTime ModuleLicenseDate { get; private set; }
每个按钮下方的标签设置为 ModuleName,并且按钮的 Content 属性设置为 ModuleAbbreviation。
我还有一个 current_user 对象,它包含一个名为 UserModules 的 ObservableCollection
public int Module_ID { get; set; }
public int User_Module_Access { get; set; }
使用 ModuleCollection 和 current_user.UserModules 列表,我想在以下场景下启用按钮:
- 如果 Module.Disabled = false
- 和 Module.ModuleLicenseDate > Now()
- 和 UserModule.User_Module_Access > 0
否则按钮将被禁用。
其他需要注意的是:UserModules 可能只有 ModuleCollection 的一个子集,ModuleCollection 将是静态的,但 UserModules 中的属性会不时刷新。
我的问题是:如何绑定这两个集合,以便它们创建我的按钮并基于两者设置 IsEnabled 属性?
[编辑] 2013-12-07
<Button.IsEnabled>
<MultiBinding Converter="{Binding viewmodel:IsEnabledMultiValueConverter}">
<Binding Source="{Binding ModuleID}" />
<Binding Source="{Binding ModuleDisabled}" />
<Binding Source="{Binding ModuleLicenseDate}" />
<Binding Source="{Binding current_user.user_modules}" />
</MultiBinding>
</Button.IsEnabled>
[EDIT2] 2013-12-09
当我更改用户模块中的模块访问级别时,事件被触发。我将值从可访问(1)更改为不可访问(0),因此按钮应该被禁用,但这不会发生。
public class UserModule : INotifyPropertyChanged
{
public UserModule(int Module_ID, int User_Module_Access)
{
this.Module_ID = Module_ID;
this.User_Module_Access = User_Module_Access;
}
private int _userModuleAccess;
public int Module_ID { get; set; }
public int User_Module_Access
{
get { return _userModuleAccess; }
set
{
_userModuleAccess = value;
MessageBox.Show("User_Module_Access");
RaisePropertyChanged("User_Module_Access");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
我的想法是,当项目属性更改时,需要发生 ObservableCollection
User 类中的一些方法?
public class User
{
public string UserName { get; set; }
public ObservableCollection<UserModule> UserModules = new ObservableCollection<UserModule>();
}
[Edit3] 2013-12-10 重做 - 实施 ItemsObservableObservableCollection
启动器.XAML
<Button Content="{Binding ModuleAbbreviation}"
Style="{DynamicResource LauncherButton}"
Background="{Binding ModuleColor}"
FontSize="32" FontFamily="Tahoma" Width="130" Height="100"
Command="{Binding DataContext.LaunchCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding ModuleName}">
<Button.Resources>
<viewmodel:IsEnabledMultiValueConverter x:Key="converter" />
</Button.Resources>
<Button.IsEnabled>
<MultiBinding Converter="{StaticResource converter}">
<Binding Path="ModuleID" />
<Binding Path="ModuleEnabled" />
<Binding Path="ModuleLicenseDate" />
<Binding ElementName="gridModules" Path="DataContext.CurrentUser" />
</MultiBinding>
</Button.IsEnabled>
</Button>
LauncherViewModel.cs
class LauncherViewModel
{
public LauncherViewModel()
{
timer = new Timer(SetModuleAccess, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
}
int pass = 0;
bool _isEnabled = false;
Timer timer;
private void SetModuleAccess(object state)
{
if (pass > 0)
{
if (_isEnabled)
_isEnabled = false;
else
_isEnabled = true;
foreach (Users.UserModule uModule in ups.model.ups_repository._current_user.UserModules)
{
if (uModule.Module_ID == 0)
{
if (_isEnabled == false)
uModule.User_Module_Access = 0;
else
uModule.User_Module_Access = 1;
}
}
if (pass == 2)
ups.model.ups_repository._current_user.UserModules.Add(new Users.UserModule(8, 1));
}
pass++;
}
public Users.User CurrentUser
{
get { return ups.model.ups_repository._current_user; }
}
public ObservableCollection<Module> ModuleCollection
{
get { return ModuleKey._module_objects; }
}
}
public class IsEnabledMultiValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
bool userHasAccess = false;
int ModuleID = (int)values[0];
bool ModuleEnabled = (bool)values[1];
string ModuleLicenseDate = (string)values[2];
Users.User user = values[3] as Users.User;
Users.UserModule userModule = user.UserModules.SingleOrDefault(um => um.Module_ID == ModuleID);
DateTimeFormatInfo dtfi = new DateTimeFormatInfo();
dtfi.ShortDatePattern = "yyyy-MM-dd";
dtfi.DateSeparator = "-";
DateTime MLicenseDate = System.Convert.ToDateTime(ModuleLicenseDate, dtfi);
if (userModule != null)
{
userHasAccess = userModule.User_Module_Access > 0;
}
return (ModuleEnabled && (MLicenseDate >= DateTime.Now) && userHasAccess);
}
catch
{
return false;
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
用户.cs
public class User : INotifyPropertyChanged
{
public static User CreateNewUser()
{
return new User();
}
public User() {}
public int User_ID { get; set; }
public string Username { get; set; }
public string Name { get; set; }
public string Job_Title { get; set; }
public string Department { get; set; }
public string Company { get; set; }
public string Phone_Office { get; set; }
public string Phone_Mobile { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public DateTime Last_Login { get; set; }
public int Status { get; set; }
public int Session_Timeout { get; set; }
private ItemsObservableObservableCollection<UserModule> user_modules = new ItemsObservableObservableCollection<UserModule>();
public ItemsObservableObservableCollection<UserModule> UserModules
{
get
{
return user_modules;
}
set
{
user_modules = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
UserModule.cs
public class UserModule : INotifyPropertyChanged
{
public UserModule(int Module_ID)
{
this.Module_ID = Module_ID;
}
public UserModule(int Module_ID, int User_Module_Access)
{
this.Module_ID = Module_ID;
this.User_Module_Access = User_Module_Access;
}
private int _module_id;
private int _userModuleAccess;
public int Module_ID
{
get { return _module_id; }
set
{
_module_id = value;
RaisePropertyChanged("Module_ID");
}
}
public int User_Module_Access
{
get { return _userModuleAccess; }
set
{
_userModuleAccess = value;
RaisePropertyChanged("User_Module_Access");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
ups.cs
namespace ups.model
{
public static class ups_repository
{
public static Users.User _current_user = new Users.User();
public static void LoadUser(string Username, string Key, string Message)
{
...
}
}
}
此时按钮正在显示,在上面的 VM 中,我将集合中的第一个用户模块从启用切换到禁用,每五秒钟。我还为集合中的最后一个添加了权限。按钮未启用并按应有的方式禁用。
【问题讨论】:
-
如果自定义 observable 集合类有助于克服集合不监听包含对象变化的问题,请参见下文“实现 ItemsObservableObservableCollection”。
-
我想,我明白了。 User.user_modules 是一个字段。请尝试将其更改为属性。
-
我以为你使用 User 对象作为 DataContext,所以,建议将 user_modules 作为 User 类中的属性。您面临的具体问题是什么?您能看到在 UI 上创建的按钮吗?什么是 DataContext 是 User 还是 UserModules 集合?要将 DataContext 绑定到哪个控件?
-
对不起,我一直在尝试各种事情来让它工作。我现在已经将事情重置为原来的样子。我删除了[EDIT4]并刷新了[EDIT3]中的代码并添加了注释。
-
应该在路上
标签: c# wpf data-binding mvvm