此时此刻,我正在使用WPF和MVVM。我在UniformGrid中有30个按钮,每个按钮都有特定的DynamicResource和特定的内容(文本)。我需要管理每个按钮的可见性,但我不想为每个按钮执行变量。
我正在考虑创建一个可见性列表并绑定此列表。但是我不想丢失UniformGrid,只是我希望在不同的按钮中绑定列表的每个元素。
答案 0 :(得分:1)
您可以通过指定索引直接绑定到列表中的项目。
<Button Content="Button 1" Visibility="{Binding Visibilities[0]}" />
<Button Content="Button 2" Visibility="{Binding Visibilities[1]}" />
<Button Content="Button 3" Visibility="{Binding Visibilities[2]}" />
在ViewModel
中定义可见性Visibilities = new List<Visibility>()
{ Visibility.Visible, Visibility.Collapsed, Visibility.Visible};
您只需确保在更改列表中的值时引发PropertyChanged事件,以便控件注意到更改。
var handler = PropertyChanged;
if (handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Visibilities"));
}
答案 1 :(得分:0)
编辑这很疯狂,请不要尝试。
这不适合胆小的人,但有一种可能性是使用运行时类型系统来实现自定义属性。您可以定制自定义类型以显示所需的属性,同时仍在内部维护可见性列表。使用这样的简单属性:
<Button Visibility="{Binding Visibilities.V1}" />
<Button Visibility="{Binding Visibilities.V2}" />
然后,您希望“Visibilities”对象实现一个实现“ICustomTypeProvider”的类,包装适当的数据(Visibility
数组)。它还应该为底层值公开一个索引器,并且setter应该引发“PropertyChanged”:
public class VisibilitiesClass : ICustomTypeProvider, INotifyPropertyChanged
{
public Visibility[] Visibilities { get; private set; };
public VisibilitiesClass(int count)
{
Visibilities = new Visibility[count];
for (int i = 0; i < count; i++)
Visibilities[i] = Visibility.Collapsed;
}
public Type GetCustomType()
{
return new VisibilitiesType(Visibilities.Length);
}
public Visibility this[int index]
{
get { return Visibilities[index]; }
set
{
Visibilities[index] = value;
RaisePropertyChanged("V" + index);
}
}
}
上面引用的VisibilitiesType
应该扩展Type
,并根据需要返回属性列表(“V1”,“V2”,...,“Vn”):
public class VisibilitiesType : Type
{
private int _count;
public VisibilitiesType(int count)
{
_count = count;
}
public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
{
return Enumerable.Range(1, _count).Select(i => new VisibilityProperty(i)).ToArray();
}
}
最后,“VisibilityProperty”应该扩展“PropertyInfo”,并从宿主对象返回适当的值:
public class VisibilityProperty : PropertyInfo
{
private int _index;
public VisibilityProperty(int index)
{
_index = index;
}
public override string Name
{
get { return "V" + _index; }
}
public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
{
var host = obj as VisibilitiesClass;
return host[_index];
}
}
请注意,上面的实现非常省略 - “Type”和“PropertyInfo”都有很多虚拟方法,其中一些可能需要覆盖。
答案 2 :(得分:0)
最好的解决方案是创建ExpandObject。
我创建了一个ExpandObject作为Dictonary
var visibilitiesAsDictionary = new ExpandoObject() as IDictionary<string, Object>;
然后我添加所有变量,在字符串中我把变量的名称和Object的值。
visibilitiesAsDictionary.Add("Item1", Visibility.Visible);
visibilitiesAsDictionary.Add("Item2", Visibility.Visible);
创建动态变量
之后private dynamic _visibilities;
public dynamic Visibilities
{
get { return _visibilities; }
set { _visibilities = value; RaisePropertyChanged("Visibilities"); }
}
然后,
Visibilities = visibilitiesAsDictionary
在Xaml中我绑定了属性
<Button Command="{Binding Item1Command}" Visibility="{Binding Visibilities.Item1}">
<Button Command="{Binding Item2Command}" Visibility="{Binding Visibilities.Item2}">
因此,当我初始化Dictionary时,按顺序无关紧要,因为该属性将绑定特定名称。