这是使用C#和MVVM。
目前,我通过绑定ObservableCollection< Module>创建了一组按钮。名为ModuleCollection。
模块定义为:
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对象,它包含一个ObservableCollection< UserModule>称为UserModules UserModule定义为:
public int Module_ID { get; set; }
public int User_Module_Access { get; set; }
使用ModuleCollection和current_user.UserModules列表,我想在以下场景下启用按钮:
否则该按钮将被禁用。
需要注意的其他事项是: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
当我更改用户模块中的模块访问级别时,事件将被触发。我将值从accessible(1)更改为unaccessible(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的事件&lt; UserModule&gt;需要在项属性更改时发生。我已经读过ObservableCollections不这样做,只添加,删除和移动项目。怎么做?
User类中的一些内容?
public class User
{
public string UserName { get; set; }
public ObservableCollection<UserModule> UserModules = new ObservableCollection<UserModule>();
}
[编辑3] 2013-12-10重做 - 实施ItemsObservableObservableCollection
Launcher.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();
}
}
User.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中,我将集合中的第一个用户模块从启用切换为禁用,每隔五秒钟。我还为集合中的最后一个添加了权限。按钮未启用并禁用它们的方式。
答案 0 :(得分:1)
您可以在Button的IsEnabled属性上使用MultiValueConverter尝试MultiBinding。 MultiValueConverter将模块绑定到Button;以及当前用户的Module Collection(在下面的示例中,我发送了用户自己)并进行测试以返回bool以指示是否可以启用或禁用Button。
<Window x:Class="WpfHowTo.ItemsControlTestHorn"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:WpfHowTo"
Title="ItemsControlTestHorn" Height="300" Width="300">
<Window.Resources>
<l:MultiValueConverter x:Key="multiValueConverter"/>
</Window.Resources>
<Grid Name="gridModules">
<ItemsControl ItemsSource="{Binding Path=Modules}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button Content="{Binding ModuleAbbreviation}">
<Button.IsEnabled>
<MultiBinding Converter="{StaticResource multiValueConverter}">
<Binding Path="."/>
<Binding ElementName="gridModules" Path="DataContext.CurrentUser"/>
<!--<Binding RelativeSource="{RelativeSource AncestorType=Grid}" Path="DataContext.CurrentUser"/>-->
</MultiBinding>
</Button.IsEnabled>
</Button>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
MultiValueConverter就是这样的。
public class MultiValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool result = true;
Module module = values[0] as Module;
User user = values[1] as User;
bool userHasAccess = false;
UserModule userModule = user.UserModules.SingleOrDefault(um => um.Module_ID == module.Module_ID);
if (userModule != null)
{
userHasAccess = userModule.User_Module_Access == 1;
}
return result = ! module.ModuleDisabled && module.ModuleLicenseDate > DateTime.Now && userHasAccess;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
班级定义
public class Module
{
public int Module_ID { get; set; }
public string ModuleName { get; set; }
public string ModuleAbbreviation { get; set; }
public bool ModuleDisabled { get; set; }
public DateTime ModuleLicenseDate { get; set; }
}
public class UserModule
{
public int Module_ID { get; set; }
public int User_Module_Access { get; set; }
}
public class User
{
private ObservableCollection<UserModule> _userModules = new ObservableCollection<UserModule>();
public string UserName { get; set; }
public ObservableCollection<UserModule> UserModules
{
get
{
return _userModules;
}
}
}
答案 1 :(得分:1)
我想出了一个更简单的想法。但是,我将第一个答案作为MultiBinding的示例。
这是新想法。我使用其他两个集合创建了一个新集合。这项技术现在符合问题的标题。
public IEnumerable<object> Modules
{
get
{
ObservableCollection<Module> modules = GetAllModules();
User currentUser = GetCurrentUser();
var accessibleModules = modules.GroupJoin
(
currentUser.UserModules, m => m.Module_ID, um => um.Module_ID,
(m, um) => new
{
ModuleName = m.ModuleName,
ModuleAbbreviation = m.ModuleAbbreviation,
IsModuleAccessible = !m.ModuleDisabled && m.ModuleLicenseDate > DateTime.Now && (um.Count() == 0 ? -1 : um.Single().User_Module_Access) == 1
}
);
return accessibleModules;
}
}
在.xaml
中<ItemsControl ItemsSource="{Binding Path=Modules}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button Content="{Binding ModuleAbbreviation}" IsEnabled="{Binding IsModuleAccessible}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
答案 2 :(得分:1)
以下类旨在克服ObservableCollection不侦听所包含对象更改的问题。
先决条件是添加到此集合的对象应实现INotifyPropertyChanged接口。
简而言之,这个类注册到项目的PropertyChanged事件并上升ObservableCollection的CollectionChanged事件。
http://msdn.microsoft.com/en-us/magazine/dd252944.aspx
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Collections;
namespace VJ.Collections
{
/// <summary>
/// This class adds the ability to refresh the list when any property of
/// the objects changes in the list which implements the INotifyPropertyChanged.
///
/// </summary>
/// <typeparam name="T">
/// The type of elements in the collection.
/// </typeparam>
public class ItemsObservableObsrvableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
RegisterPropertyChanged(e.NewItems);
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
UnRegisterPropertyChanged(e.OldItems);
}
else if (e.Action == NotifyCollectionChangedAction.Replace)
{
UnRegisterPropertyChanged(e.OldItems);
RegisterPropertyChanged(e.NewItems);
}
base.OnCollectionChanged(e);
}
protected override void ClearItems()
{
UnRegisterPropertyChanged(this);
base.ClearItems();
}
private void RegisterPropertyChanged(IList items)
{
foreach (INotifyPropertyChanged item in items)
{
item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}
}
private void UnRegisterPropertyChanged(IList items)
{
foreach (INotifyPropertyChanged item in items)
{
item.PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
}
}
private void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
}