我正在WPF中构建一个类似Visual Studio的应用程序,我在识别组件的最佳架构设计组织时遇到了一些问题.我计划使用Unity作为我的依赖注入容器和Visual Studio单元测试框架,并且可能使用moq来模拟库.
我将首先描述我的解决方案的结构,然后我的问题:
我有一个WPF项目,其中包含:
另一个名为ViewModel的项目包含:
我的初始化逻辑如下:
var window = Container.Resolve<MainView>();
window.Show();
我的MainView构造函数在其构造函数中接收MainViewModel对象:
public MainView(MainViewModel _mvm)
Run Code Online (Sandbox Code Playgroud)
我的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)
缺点:
选项2:通过注释我的属性来使用setter注入:
[Dependency]
public ToolboxViewModel ToolboxVM{get; set;}
//... Same for rest …
Run Code Online (Sandbox Code Playgroud) 我试图将列表父项之类的通用列表绑定到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?
阿道夫先生,先谢谢你
好吧,我有一个在基类中定义的依赖属性,我试图在其派生类的构造函数中使用它,但是这不起作用,该属性显示为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
我的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) 我正在研究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)
谢谢!
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
。众所周知,这是导致此异常的原因。所以我的结论是:
DateTime
将在 SQL Server …这是一个从最初发布的问题扩展到的问题: 链接到loading-xaml到运行时
我正在开发一个WPF MVVM应用程序,它从外部源动态加载XAML内容,与上面的帖子中的答案非常相似.
这是我到目前为止所得到的:
我的问题是,如何消除代码隐藏和自动化逻辑,以便View可以在ViewModel完成获取XAML内容并初始化字符串属性后立即动态呈现新的xaml部分?
我应该使用某种消息总线,以便ViewModel在设置属性后通知,以便View可以添加新内容吗?
让我感到困扰的是,ViewModel确实有对Views的引用,不应该负责生成UI元素.
提前致谢!
编辑:只是为了澄清:在我的特定情况下,我不是试图将业务对象或集合(模型)绑定到UI元素(例如网格),这显然可以通过模板和绑定来完成.我的ViewModel正在从外部源检索整个XAML表单,并将其设置为View可用的字符串属性.
我的问题是:谁应该负责将这个XAML字符串属性反序列化为UI元素,并在设置VM中的Xaml字符串属性后以编程方式将其添加到我的网格中?
这听起来更像是一个View责任,而不是ViewModel.但我理解的模式强制要用V-VM绑定替换任何代码隐藏逻辑.
我有以下格式的数据:
MM:SS:嗯,其中MM is minutes
,ss is seconds
和mmm 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位毫秒
我有以下课程:
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) 我对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) 我有一个对象列表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)
有任何想法吗??
我目前正在使用MVVM设计模式开发Enterprise WPF LOB Desktop应用程序。我当前在开发机器中的解决方案结构如下:
我目前不使用WCF,因为目前所有内容都驻留在同一台计算机上,但数据库位于其自己的服务器中。但是,将来我们计划将代码库分为3层。
我的问题是,一位同事坚持认为,我们应按以下步骤在3台单独的服务器/机器中拆分应用程序:
我无法想象的视图模型从分开居住(不同的服务器)查看,他声称,应该是可能的。
编辑:我的同事声称,在服务器端具有视图模型将简化将来的任何部署,并使它更易于维护,因为更改只会在服务器端进行。但是,我已经使用ClickOnce部署了.NET应用程序,但这并不是什么大问题。
根据我的阅读,您可以在用户计算机上安装一个包含View和ViewModel的WPF客户端应用程序,然后通过诸如WCF的通信层在较低层公开服务。
该答案在另一篇文章中指出: “在MVVM中,UI层分为两层:负责应用逻辑的ViewModel和仅负责演示的View。” 基于此,我的基本问题是,View和ViewModel UI层可以位于单独的层(服务器)中吗?如果是这样,建议吗?以及如何实现?
谢谢!
c# ×9
mvvm ×4
wpf ×3
.net ×2
binding ×2
linq ×2
architecture ×1
c#-4.0 ×1
combobox ×1
containers ×1
datetime ×1
dynamic ×1
expression ×1
generic-list ×1
generics ×1
inheritance ×1
regex ×1
replace ×1
runtime ×1
unit-testing ×1
winforms ×1