小编Ado*_*rez的帖子

具有Unity和单元测试的MVVM架构设计

我正在WPF中构建一个类似Visual Studio的应用程序,我在识别组件的最佳架构设计组织时遇到了一些问题.我计划使用Unity作为我的依赖注入容器和Visual Studio单元测试框架,并且可能使用moq来模拟库.

我将首先描述我的解决方案的结构,然后我的问题:

我有一个WPF项目,其中包含:

  • 应用程序启动时的Unity容器初始化(引导程序)(在App.xaml.cs中)
  • 我的所有应用程序视图(XAML).

另一个名为ViewModel的项目包含:

  • 我的所有应用程序ViewModels.我的所有ViewModel都从一个暴露ILogger属性的ViewModelBase继承

我的初始化逻辑如下:

  1. 应用程序启动
  2. Unity容器创建和类型注册:MainView和MainViewModel
  3. 解析我的MainView并显示它.

var window = Container.Resolve<MainView>();

window.Show();

我的MainView构造函数在其构造函数中接收MainViewModel对象:

public MainView(MainViewModel _mvm)
Run Code Online (Sandbox Code Playgroud)
  1. 我的MainViewModel为每个面板都有一个Child ViewModel:

    public ToolboxViewModel ToolboxVM{get; set;}
    public SolutionExplorerViewModel SolutionExplorerVM { get; set; }
    public PropertiesViewModel PropertiesVM { get; set; }
    public MessagesViewModel MessagesVM { get; set; }
    
    Run Code Online (Sandbox Code Playgroud)

我打算创建一个初始化每个面板的InitializePanels()方法.

现在我的问题是:我的MainViewModel.InitializePanels()如何初始化所有这些面板?给出以下选项:

选项1:手动初始化ViewModels:

ToolboxVM = new ToolboxViewModel();
//Same for the rest of VM...
Run Code Online (Sandbox Code Playgroud)

缺点:

  • 我没有使用Unity容器,因此我的依赖项(例如ILogger)不会自动解析

选项2:通过注释我的属性来使用setter注入:

[Dependency]
public ToolboxViewModel ToolboxVM{get; set;}
//... Same for rest …
Run Code Online (Sandbox Code Playgroud)

c# architecture unit-testing unity-container mvvm

8
推荐指数
1
解决办法
4019
查看次数

如何将ComboBox绑定到具有深DisplayMember和ValueMember属性的泛型List?

我试图将列表父项之类的通用列表绑定到ComboBox.

    public Form1()
    {
        InitializeComponent();
        List<Parent> parents = new List<Parent>();
        Parent p = new Parent();
        p.child = new Child();
        p.child.DisplayMember="SHOW THIS";
        p.child.ValueMember = 666;
        parents.Add(p);
        comboBox1.DisplayMember = "child.DisplayMember";
        comboBox1.ValueMember = "child.ValueMember";
        comboBox1.DataSource = parents;
    }
}
public class Parent
{
    public Child child { get; set; }
}
public class Child
{
    public string DisplayMember { get; set; }
    public int ValueMember { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

当我运行我的测试应用程序时,我只看到:"ComboBindingToListTest.Parent"显示在我的ComboBox中,而不是"显示它".如何通过一个级别或更深层的属性将ComboBox绑定到通用列表,例如child.DisplayMember?

阿道夫先生,先谢谢你

c# binding combobox generic-list winforms

6
推荐指数
1
解决办法
1万
查看次数

使用Unity的构造函数中使用的属性依赖注入

好吧,我有一个在基类中定义的依赖属性,我试图在其派生类的构造函数中使用它,但是这不起作用,该属性显示为null.Unity使用container.Resolve()解析实例后解析依赖属性;

我有一个替代方法是将IUnityContainer参数添加到我的MyViewModel类构造函数中,并将ILogger属性设置为我自己,例如:

public MyViewModel(IUnityContainer container)
{
  Logger = container.Resolve<ILogger>();
}
Run Code Online (Sandbox Code Playgroud)

编辑: @Wiktor_Zychla的另一个建议是将构造函数注入的参数传递为:

public MyViewModel(ILogger _logger)
{
    Logger = _logger;
}
Run Code Online (Sandbox Code Playgroud)

这似乎工作正常,但我必须为我的所有派生的ViewModel做到这一点..

但后来我没有在我的基类中使用带注释的ILogger依赖项.请参阅下面的课程示例.问题是:我有哪些替代方案,或者我做错了什么?

谢谢!

我有一个像这样的ViewModel基类:

public abstract class ViewModelBase
{
    [Dependency]
    public ILogger Logger { get; set; }
....
}
Run Code Online (Sandbox Code Playgroud)

然后我有一个类推导出:

public class MyViewModel : ViewModelBase
{
    public MyViewModel()
    {
         //I want to use my dependent property in constructor, but doesn't 

         Logger.Error("PRINT AN ERROR");
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的应用程序入口点,我将我的ILogger注册为单例和我的MyViewModel类:

container.RegisterType<ILogger, MyAppLogger>(new ContainerControlledLifetimeManager());
container.RegisterType<MyViewModel>();
Run Code Online (Sandbox Code Playgroud)

c# containers dependency-injection inversion-of-control unity-container

5
推荐指数
1
解决办法
5315
查看次数

修剪结束节点满足某些条件的树枝

我的TreeNode课如下:

public class TreeNode
{
    public enum NodeType { Root,Element, Category}
    public TreeNode()
    {
        Children = new List<TreeNode>();
    }
    public List<TreeNode> Children { get; set; }
    public string Name { get; set; }
    public NodeType Type { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我有一个BuildTree填充树结构的方法,为每个节点设置节点名称和类型(例如,第一个节点将设置为“根类型”,子节点可以是“元素”或“类别”类型)。

我正在寻找一种有效的方法(也许使用LINQ)修剪末端节点类型不是Category的树枝。关于如何实现这一目标的任何想法?

这里是一个可视示例:

之前

Root
|
|_ NodeA (Element)
|_ Node B (Element)
|  |_ Node B.1 (Category)
|_ Node C (Element)
|  |_ Node C.1 (Element)
|    |_Node C.1.1 (Category)
|_ Node D …
Run Code Online (Sandbox Code Playgroud)

c# linq

5
推荐指数
1
解决办法
995
查看次数

EF5如何获取域对象的导航属性列表

我正在研究EF 5 Code-First解决方案,我正在尝试使用Repository模式更新现有实体并使用已修改的实体:

    public void UpdateValues(T originalEntity, T modifiedEntity)
    {
        _uow.Context.Entry(originalEntity).CurrentValues.SetValues(modifiedEntity);
Run Code Online (Sandbox Code Playgroud)

我的简化域对象如下所示:

public class PolicyInformation : DomainObject
{
     //Non-navigation properties
     public string Description {get;set;}
     public bool Reinsurance {get;set;}
     ...
     //Navigation properties
     LookupListItemFormType FormType {get;set;}
     ...
}
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是该CurrentValues.SetValues(modifiedEntity);方法似乎只更新标量和复杂类型属性,但不更新导航属性.我已经看到这种情况发生在很多人身上,但仍然不知道为什么会这样.但是,我发现如果我在执行后手动设置这些导航属性,UpdateValues一切正常:

            _policyInfoRepo.UpdateValues(existingPolicyInfo, info);
            existingPolicyInfo.FormType = info.FormType;
Run Code Online (Sandbox Code Playgroud)

问题是,因为我使用通用存储库:如何在域对象中获取导航属性列表?也许通过linq,反射或任何其他方式,以便我的存储库中的更新方法可以循环遍历它们并自动设置它们?

像这样的东西:

    public void UpdateValues(T originalEntity, T modifiedEntity)
    {
        //Set non-nav props
        _uow.Context.Entry(originalEntity).CurrentValues.SetValues(modifiedEntity);
        //Set nav props
        var navProps = GetNavigationProperties(originalEntity);
        foreach(var navProp in navProps)
        {
           //Set originalEntity prop value to modifiedEntity value
        }
Run Code Online (Sandbox Code Playgroud)

谢谢!

entity-framework navigation-properties c#-4.0

4
推荐指数
2
解决办法
7693
查看次数

当值为 null 时,实体框架 6 中的可为 Null DateTime 属性在保存时会引发异常

DateTime我在我的一个类中定义了一个 Nullable属性:

public DateTime? ControlDate { get; set; }
Run Code Online (Sandbox Code Playgroud)

当使用 EF 6 CodeFirst 从我的模型生成数据库 (SQL Server 2008) 时,我得到:

控制日期为空

问题是,当我保存实例时,ControlDate=null出现以下异常:

conversion of a datetime2 data type to a datetime data type
resulted in an out-of-range value
Run Code Online (Sandbox Code Playgroud)

我读过多篇相关的帖子和​​文章,说这种情况通常发生在您定义不可为空的 DateTime 属性并尝试在之前未设置有效日期的情况下保存它时,有些人建议将该属性设置为可空,以防属性值可以为空。 null(这是我的特殊情况)。

我的问题是:当我的属性和列类型可为空时,为什么 EF 会尝试设置默认日期。Null 应该是一个有效值,并且应该一直流到数据库,中间没有任何其他转换。

这里有一篇相关文章:Conversion of a datetime2 data type to a datetime data type results out-of-range value

编辑::这是一个非常相似的问题。非常详细的解释,如果有人感兴趣的话。

经验教训: 只是想澄清一下,仔细观察后,我发现这是我这边的问题。在保存我的对象之前,它被设置为:

myObject.ControlDate = new DateTime()
Run Code Online (Sandbox Code Playgroud)

在检查时,它显示了默认的不兼容日期1/1/0001。众所周知,这是导致此异常的原因。所以我的结论是:

  • 声明不可为 null 的属性的模型DateTime将在 SQL Server …

.net c# datetime entity-framework-6

4
推荐指数
1
解决办法
1万
查看次数

使用WPF中的MVVM模式在运行时加载XAML

这是一个从最初发布的问题扩展到的问题: 链接到loading-xaml到运行时

我正在开发一个WPF MVVM应用程序,它从外部源动态加载XAML内容,与上面的帖子中的答案非常相似.
这是我到目前为止所得到的:

  1. My View将ViewModel的实例声明为资源,并创建该ViewModel的实例
  2. 在我的ViewModel构造函数中,我正在加载来自外部源(文件或数据库..)的XamlString属性.
  3. 在我看来,我有一个用户在ViewModel完成加载后点击的按钮,在点击事件代码隐藏中,我将动态加载的XAML反序列化并将其添加到我的网格中.

我的问题是,如何消除代码隐藏和自动化逻辑,以便View可以在ViewModel完成获取XAML内容并初始化字符串属性后立即动态呈现新的xaml部分?

我应该使用某种消息总线,以便ViewModel在设置属性后通知,以便View可以添加新内容吗?

让我感到困扰的是,ViewModel确实有对Views的引用,不应该负责生成UI元素.

提前致谢!

编辑:只是为了澄清:在我的特定情况下,我不是试图将业务对象或集合(模型)绑定到UI元素(例如网格),这显然可以通过模板和绑定来完成.我的ViewModel正在从外部源检索整个XAML表单,并将其设置为View可用的字符串属性.

我的问题是:谁应该负责将这个XAML字符串属性反序列化为UI元素,并在设置VM中的Xaml字符串属性后以编程方式将其添加到我的网格中?
这听起来更像是一个View责任,而不是ViewModel.但我理解的模式强制要用V-VM绑定替换任何代码隐藏逻辑.

.net c# wpf dynamic mvvm

3
推荐指数
1
解决办法
7719
查看次数

正则表达式替换字符的第二次出现

我有以下格式的数据:

MM:SS:嗯,其中MM is minutesss is secondsmmm is 3 digit milliseconds,如:

05:23:236
Run Code Online (Sandbox Code Playgroud)

我正在尝试用点替换第二次出现的冒号:

05:23.236
Run Code Online (Sandbox Code Playgroud)

我想使用一种regex模式在Notepad ++之类的编辑器中进行替换,我想出了这个正则表达式来匹配我的表达式:

 \d{1,2}:\d{1,2}:\d{1,3}
Run Code Online (Sandbox Code Playgroud)

但是现在我如何才能只得到second occurrence of colon以便可以替换为dot

编辑:请注意,我正在使用的数据可能带有1-2位数字分钟,1-2位数字秒和1-3位毫秒

regex replace

3
推荐指数
1
解决办法
9764
查看次数

如何在C#中使用派生类型重写泛型方法

我有以下课程:

public interface IService
{
    void ApplyChanges<T>(T parameters) where T : ParamBase;
}

public class ServiceBase : IService
{
    public virtual void ApplyChanges<T>(T parameters) where T : ParamBase
    { }
}
public abstract class Service : ServiceBase
{
    public override void ApplyChanges<T>(T parameters) where T : ParamBase
    {
        Console.WriteLine(parameters.Param2);
        //Apply changes logic here...
    }
}

public abstract class ParamBase
{
    public string Param1 { get; set; }
}

public class ParamA : ParamBase
{
    public string Param2 { get; set; …
Run Code Online (Sandbox Code Playgroud)

c# generics inheritance

3
推荐指数
2
解决办法
6071
查看次数

MVVM INotifyPropertyChanged与基类PropertyChange冲突

我对MVVM比较陌生,我试图了解INotifyPropertyChanged接口的工作原理以及如何在我的模型中实现它.我决定采用的方法是在每个Business Object类中实现它.
这种方法的问题在于,当我将View绑定到Base类中的属性时,该基类中的PropertyChanged事件永远不会被初始化(为null),因此当我的Model更改时,View不会刷新该元素的数据.我能够通过下面的例子重现问题.

我有一个Person Base类:

 public class Person : INotifyPropertyChanged
    {
        #region INotifyProperty

        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

        public String Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
                RaisePropertyChanged("Name");
            }
        }
        private String _name;
    }
Run Code Online (Sandbox Code Playgroud)

我有一个继承自Person Base类的Employee类:

 public class Employee : Person,INotifyPropertyChanged
    {
        #region INotifyProperty

        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new …
Run Code Online (Sandbox Code Playgroud)

c# wpf binding mvvm inotifypropertychanged

2
推荐指数
1
解决办法
4961
查看次数

如何在运行时生成 lambda,将属性名称作为字符串传递?

我有一个对象列表PolicyTran

List<PolicyTran> AllTransactions;
Run Code Online (Sandbox Code Playgroud)

我需要按属性运行查询过滤,例如:

var insureds = AllTransactions.Select(x => x.Insured).ToList();
Run Code Online (Sandbox Code Playgroud)

这工作正常,但我需要x.Insured在运行时传递该属性,因为该属性可能采用不同的值。

我尝试这样做:

ParameterExpression x = Expression.Parameter(typeof (PolicyTran),"x");
MemberExpression body = Expression.Property(x, propertyName);
var lambda = Expression.Lambda(body,x).Compile();
var result = AllTransactions.Select(lambda).ToList();
Run Code Online (Sandbox Code Playgroud)

在这种情况下propertyName包含“被保险人”或任何其他PolicyTran财产。但我收到一个编译错误,指出“类型参数无法通过用法推断...”

我也尝试过,但没有运气:

ParameterExpression x = Expression.Parameter(typeof (PolicyTran),"x");
var result = AllTransactions.Select(Expression.Lambda<Func<PolicyTran, bool>>(x).Compile()).ToList();
Run Code Online (Sandbox Code Playgroud)

有任何想法吗??

c# linq expression runtime

2
推荐指数
1
解决办法
619
查看次数

MVVM WPF在三层架构中的应用

我目前正在使用MVVM设计模式开发Enterprise WPF LOB Desktop应用程序。我当前在开发机器中的解决方案结构如下:

  • 主项目 -包含所有视图(XAML)的WPF应用程序
  • 视图模型 -包含备份主项目中视图的所有视图模型
  • BLL -业务逻辑层
  • DAL-数据访问层-连接到MS-SQL服务器并调用存储过程
  • 模型 -包含所有业务实体

我目前不使用WCF,因为目前所有内容都驻留在同一台计算机上,但数据库位于其自己的服务器中。但是,将来我们计划将代码库分为3层。

我的问题是,一位同事坚持认为,我们应按以下步骤在3台单独的服务器/机器中拆分应用程序:

  1. 表示层 - 用户计算机中的客户端WPF应用程序(View)。这也可能是Web客户端应用程序
  2. 逻辑层服务器 -视图模型+模型+业务逻辑层+数据访问层
  3. 数据层服务器 -数据库服务器

我无法想象的视图模型从分开居住(不同的服务器)查看,他声称,应该是可能的。

编辑:我的同事声称,在服务器端具有视图模型将简化将来的任何部署,并使它更易于维护,因为更改只会在服务器端进行。但是,我已经使用ClickOnce部署了.NET应用程序,但这并不是什么大问题。

根据我的阅读,您可以在用户计算机上安装一个包含View和ViewModel的WPF客户端应用程序,然后通过诸如WCF的通信层在较低层公开服务。

该答案在另一篇文章中指出: “在MVVM中,UI层分为两层:负责应用逻辑的ViewModel和仅负责演示的View。” 基于此,我的基本问题是,View和ViewModel UI层可以位于单独的层(服务器)中吗?如果是这样,建议吗?以及如何实现?

谢谢!

wpf mvvm n-tier-architecture

1
推荐指数
1
解决办法
6260
查看次数