ObservableCollection属性类

时间:2013-01-10 15:27:39

标签: c# asp.net generics mvvm

我在MVVM项目中重复此属性的次数太多了。创建泛型类或工厂来替换这些代码行的正确方法是什么?

    ObservableCollection<Result> _resultCollection;
    public ObservableCollection<Result> ResultCollection
    {
        get
        {
            if (_resultCollection == null)
                _resultCollection = new ObservableCollection<Result>();
            return _resultCollection;
        }
        set
        {
            _resultCollection = value;
        }
    }

4 个答案:

答案 0 :(得分:3)

我知道这并不能完全回答你的问题,不过我个人更喜欢在Visual Studio中使用录制的宏来为我编写所有内容。

我更喜欢将它用于泛型类,因为它将所有相关代码保存在一个地方,并且很容易理解发生了什么。通常我将所有私有字段放在我的类的顶部,并隐藏我保持折叠的#region标记中的所有公共属性,因此我不需要滚动它们。

在VS中创建宏非常容易:只需转到工具&gt;宏&gt;记录临时宏,然后仅使用键盘执行所需的更改。一旦宏正常工作,只需将其保存为永久宏。如果你做得对,你可以用任何变量重新运行宏,它将以相同的方式构建它。

创建宏时要记住的一些有用的键盘快捷键是:

  • Ctrl + C / Ctrl + V 复制/粘贴
  • Ctrl + Right / Ctrl + Left 移动单词
  • Home / End 移动到行的开头或结尾
  • Shift 用于在移动光标时突出显示单词

您可能还需要对VB宏代码进行一些小修改,例如.Replace()将小写字母转换为大写字母。

这是我用来构建MVVM的所有公共属性的示例宏。它使用PRISM库,因此它使用语法RaisePropertyChanged(() => this.SomeProperty);

Sub PRISM_BuildPropertyChanged_CursorAtDefaultAfterCtrlRE()
    DTE.ActiveDocument.Selection.LineDown(False, 2)
    DTE.ActiveDocument.Selection.WordLeft(True)
    DTE.ActiveDocument.Selection.Copy()
    DTE.ActiveDocument.Selection.LineDown(False, 3)
    DTE.ActiveDocument.Selection.EndOfLine()
    DTE.ActiveDocument.Selection.CharLeft()
    DTE.ActiveDocument.Selection.NewLine()
    DTE.ActiveDocument.Selection.Text = "RaisePropertyChanged(() => this."
    DTE.ActiveDocument.Selection.Paste()
    DTE.ActiveDocument.Selection.Text = ");"
    DTE.ActiveDocument.Selection.LineUp()
    DTE.ActiveDocument.Selection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText)
    DTE.ActiveDocument.Selection.CharRight(False, 4)
    DTE.ActiveDocument.Selection.NewLine()
    DTE.ActiveDocument.Selection.CharRight()
    DTE.ActiveDocument.Selection.NewLine()
    DTE.ActiveDocument.Selection.Text = "if (value != "
    DTE.ActiveDocument.Selection.WordRight(True)
    DTE.ActiveDocument.Selection.Copy()
    DTE.ActiveDocument.Selection.CharLeft()
    DTE.ActiveDocument.Selection.Paste()
    DTE.ActiveDocument.Selection.DeleteLeft()
    DTE.ActiveDocument.Selection.Text = ")"
    DTE.ActiveDocument.Selection.NewLine()
    DTE.ActiveDocument.Selection.Text = "{"
    DTE.ActiveDocument.Selection.LineDown()
    DTE.ActiveDocument.Selection.EndOfLine()
    DTE.ActiveDocument.Selection.NewLine()
    DTE.ActiveDocument.Selection.Text = "}"
End Sub

有了它,我可以编写我的私人定义,例如

private ObservableCollection<SomeObject> _someCollection;

点击 Ctrl + R E 来构建公共属性定义

private ObservableCollection<SomeObject> _someCollection;

public ObservableCollection<SomeObject> SomeCollection
{
    get { return _someCollection; }
    set { _someCollection = value; }
}

然后运行我的宏来构建属性更改通知

public ObservableCollection<SomeObject> SomeCollection
{
    get { return _someCollection; }
    set 
    {
        if (value != _someCollection)
        {
            _someCollection = value;
            RaisePropertyChanged(() => this.SomeCollection);
        }
    }
}

(默认情况下, Ctrl + R E 将光标放在私有字段定义的末尾,这是运行此代码时光标所在的位置宏)

我还有另一个旧宏,它添加了检查值是否为null的代码,如果是,则将其设置为对象的新实例,但是我从未使用过很多,因为我更喜欢设置我的默认定义构造函数而不是属性定义。

如果你想要它,它看起来像这样(注意宏名称 - 你需要在运行这个宏之前突出显示公共属性名称):

Sub CreatePublicGet_NoNull_HightlightPropertyNameFirst()
    DTE.ActiveDocument.Selection.CharLeft(False, 2)
    DTE.ActiveDocument.Selection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText, True)
    DTE.ActiveDocument.Selection.WordRight(True)
    DTE.ActiveDocument.Selection.Copy()
    DTE.ActiveDocument.Selection.LineDown(False, 2)
    DTE.ActiveDocument.Selection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText)
    DTE.ActiveDocument.Selection.CharRight(False, 4)
    DTE.ActiveDocument.Selection.NewLine()
    DTE.ActiveDocument.Selection.CharRight()
    DTE.ActiveDocument.Selection.NewLine()
    DTE.ActiveDocument.Selection.EndOfLine()
    DTE.ActiveDocument.Selection.CharLeft()
    DTE.ActiveDocument.Selection.NewLine()
    DTE.ActiveDocument.Selection.LineUp(False, 2)
    DTE.ActiveDocument.Selection.EndOfLine()
    DTE.ActiveDocument.Selection.NewLine()
    DTE.ActiveDocument.Selection.Paste()
    DTE.ActiveDocument.Selection.Text = "();"
    DTE.ActiveDocument.Selection.LineDown()
    DTE.ActiveDocument.Selection.WordLeft(True)
    DTE.ActiveDocument.Selection.CharLeft()
    DTE.ActiveDocument.Selection.WordLeft(True)
    DTE.ActiveDocument.Selection.Copy()
    DTE.ActiveDocument.Selection.LineUp(False, 2)
    DTE.ActiveDocument.Selection.NewLine()
    DTE.ActiveDocument.Selection.Text = "if ("
    DTE.ActiveDocument.Selection.Paste()
    DTE.ActiveDocument.Selection.Text = " == null)"
    DTE.ActiveDocument.Selection.NewLine()
    DTE.ActiveDocument.Selection.Text = "{"
    DTE.ActiveDocument.Selection.LineDown()
    DTE.ActiveDocument.Selection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText)
    DTE.ActiveDocument.Selection.EndOfLine()
    DTE.ActiveDocument.Selection.NewLine()
    DTE.ActiveDocument.Selection.Text = "}"
    DTE.ActiveDocument.Selection.LineUp()
    DTE.ActiveDocument.Selection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText)
    DTE.ActiveDocument.Selection.Paste()
    DTE.ActiveDocument.Selection.Text = " = new "
    DTE.ActiveDocument.Selection.Collapse()
    DTE.ActiveDocument.Selection.EndOfLine()
    DTE.ActiveDocument.Selection.LineDown(False, 4)
    DTE.ActiveDocument.Selection.EndOfLine()
    DTE.ActiveDocument.Selection.LineUp(True)
    DTE.ActiveDocument.Selection.Delete()
End Sub

结果代码如下:

public ObservableCollection<SomeObject> SomeCollection
{
    get 
    {
        if (_someCollection == null)
        {
            _someCollection = new ObservableCollection<SomeObject>();
        }
        return _someCollection; 
    }
}

答案 1 :(得分:0)

如果没有某种形式的代码生成,AFAIK是不可能的。查看T4模板,回答here

答案 2 :(得分:0)

public abstract class XBase<T>
{
    ObservableCollection<T> _resultCollection;

    public ObservableCollection<T> ResultCollection
    {
        get
        {
            if (_resultCollection == null)
                _resultCollection = new ObservableCollection<T>();

            return _resultCollection;
        }
        set
        {
            _resultCollection = value;

        }
    }
}

答案 3 :(得分:0)

是的......能够绑定到一个字段会很棒,不会...... ;-)这会带我去第一个解决方案

(1)创建一个允许绑定字段的转换器。

public class FieldBindingConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var par = parameter as string;
        var field = value.GetType().GetField(par);
        return field.GetValue(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

然后(2)直接从XAML绑定字段:

    <ItemsControl ItemsSource="{Binding ., Converter={StaticResource Field}, ConverterParameter=Coll2}" Grid.Row="1">

我有点不喜欢这是诚实的,因为它并没有真正清楚......所以作为第二个解决方案,你可以直接从构造函数中实例化该属性:

public Foo() 
{
    ResultCollection = new ObservableCollection<Result>();
}

[...]

public ObservableCollection<Result> ResultCollection { get; private set; }

虽然这确实增加了几个字节的内存占用(它将延迟实例化的语义更改为直接实例化),但我不会太在意它。