【问题标题】:WPF- Create a list of VisibilitiesWPF-创建可见性列表
【发布时间】:2014-07-08 00:44:59
【问题描述】:

此时,我正在使用 WPF 和 MVVM。我有一个带有 30 个按钮的 UniformGrid,每个按钮都有特定的 DynamicResource 和特定的内容(文本)。我需要管理每个按钮的可见性,但我不想为每个按钮做一个变量。

我正在考虑创建一个可见性列表并绑定此列表。但我不想失去 UniformGrid,我只想将列表的每个元素绑定在不同的按钮中。

【问题讨论】:

标签: c# wpf mvvm visibility


【解决方案1】:

编辑这太疯狂了,请不要尝试。


这并不适合胆小的人,但一种可能性是使用运行时类型系统来实现自定义属性。您可以定制一个自定义类型来公开您想要的属性,同时仍然在内部维护一个可见性列表。使用像这样的简单属性:

<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”都有大量虚拟方法,其中一些您可能需要覆盖。

【讨论】:

  • 是的...这不适合胆小的人 :) (我们应该在 SO ... 中有一个胆小的徽章)
【解决方案2】:

您可以通过指定索引直接绑定到列表中的项目。

<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"));
}

【讨论】:

    【解决方案3】:

    最好的解决方案是创建 ExpandObject。

    我创建了一个 ExpandObject 作为字典

     var visibilitiesAsDictionary  = new ExpandoObject() as IDictionary<string, 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 时,我执行它的顺序并不重要,因为该属性将绑定到一个特定的名称。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-19
      • 2010-10-17
      • 2018-07-28
      • 2013-07-14
      • 2012-07-17
      • 2011-10-12
      • 2011-03-31
      • 1970-01-01
      相关资源
      最近更新 更多