1

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

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

4 回答 4

3

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

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

在 VS 中创建宏相当容易:只需转到工具 > 宏 > 记录临时宏,然后仅使用键盘执行您想要的更改。让宏正常工作后,只需将其保存为永久宏即可。如果你做对了,你可以用任何变量重新运行宏,它会以同样的方式构建它。

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

  • 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将光标放在私有字段定义的末尾,因此这是运行此宏时光标需要位于的位置)

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

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

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; 
    }
}
于 2013-01-10T15:44:15.043 回答
0

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

于 2013-01-10T15:31:12.013 回答
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; }

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

于 2013-01-11T21:10:28.707 回答
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;

        }
    }
}
于 2013-01-10T15:43:47.913 回答