在视图模型中创建控件实例
Creating control instance in viewmodel
在我的程序中,我试图设计一个输出 window 来显示日志信息。现在,我绑定到一个字符串并在日志数据输入时立即更新信息。
例如:
<FlowDocument>
<Paragraph>
<Run DataContext="{Binding}" Text="{Binding OutputText}"/>
</Paragraph>
</FlowDocument>
(流文档在富文本框内)
在我的视图模型中,这就是我更新输出文本的方式
OutputText += loggingInfoString;
问题是字符串是不可变的数据类型,我不喜欢每次有新数据进来都创建一个新字符串的想法。这是不必要的开销。
RichTextBox 有一个名为 AppendText 的方法,我认为它会使用类似于 Stringbuilder 的方法来添加到字符串中。我遇到的问题是能够访问 ViewModel 中的 AppendText。
我考虑过在 ViewModel 中创建一个 RichTextBox 实例,并将 RichTextBox 绑定到 ViewModel 中的实例。我认为这违反了 MVVM,但我不完全确定。还有另一种方法可以解决这个问题吗?或者我应该只在 ViewModel 中创建 RichTextBox 实例吗?
例如:
// 视图模型
RichTextBox Output;
// 更新方法
Output.AppendText(loggerInfoText);
// Xaml
<RichTextBox DataContext="{Binding Output}" />
提前致谢!
你像这样创建一个界面
interface IAppender{
void Append(string appendText);
}
您将此接口注入您的视图模型并在您的视图中实现它。
这意味着在您的视图模型代码中,您只需执行
appender.Append(loggerInfoText);
并且在您看来,您是通过向富文本添加文本来实现界面的。
根据视图和视图模型的实现,根据创建视图模型的位置,您可以在视图模型中注入接口。假设视图模型是在视图中创建的,您会得到如下内容:
class View : UserControl, IAppender{
View(){
InitializeComponent();
DataContext = new YourViewModel(this);
}
void Append(string appendText){
//add text to richttext
}
}
public class YourViewModel : ViewModelBase{
private IAppender _appender;
public YourViewModel(IAppender appender){
_appender = appender;
}
}
我希望这应该能让你入门
请注意,这是伪代码,甚至 运行 都没有通过编译器对其进行测试。
将 richttext 传递给 viewmodel 确实不是 MVVM。这个想法是分离关注点。通过我的界面方法,这没有被违反。
作为由您的控件实现的注入依赖项的替代方法(即使分离,也会使视图注入变得很痛苦):
首先,您可以在内部使用 StringBuilder 来构建您的字符串。
public class MyViewModel : ViewModelBase
{
private StringBuilder sb;
private string Content
{
return sb.ToString();
}
protected Append(string text) {
sb.Append(text);
PropertyChanged("Content");
}
}
然后将 Content
属性 绑定到您的 XAML 元素。这样你的 ViewModel 中就不会有 allocations/deallocations,你也不需要麻烦 DI 将你的 View/Control 注入 ViewModel(即使它是由接口抽象的)。
但是,这假设您要在任何地方都避免这种分配。如果您只想在某种类型的应用程序(即 Windows 商店应用程序)中使用它,而不是在您的 ASP.NET 或桌面应用程序中使用,则第二种选择可能更具吸引力(尤其是对于其他类似场景):
您可以使用自定义行为来实现此目的,如 中的答案所示。行为是可重用的,您不必在 ViewModel 中做出此类决定,从而允许您以不同的方式处理每个平台甚至每个视图。
并且它简化了您的 ViewModel,您将不必费心如何将实现 IAppender
的 View 注入到您的 ViewModel 中(这可能会在 View-first 方法中引起麻烦,其中 View 由IoC 并获取注入到视图中的 ViewModel 以设置为 DataContext)
在我的程序中,我试图设计一个输出 window 来显示日志信息。现在,我绑定到一个字符串并在日志数据输入时立即更新信息。
例如:
<FlowDocument>
<Paragraph>
<Run DataContext="{Binding}" Text="{Binding OutputText}"/>
</Paragraph>
</FlowDocument>
(流文档在富文本框内)
在我的视图模型中,这就是我更新输出文本的方式
OutputText += loggingInfoString;
问题是字符串是不可变的数据类型,我不喜欢每次有新数据进来都创建一个新字符串的想法。这是不必要的开销。
RichTextBox 有一个名为 AppendText 的方法,我认为它会使用类似于 Stringbuilder 的方法来添加到字符串中。我遇到的问题是能够访问 ViewModel 中的 AppendText。
我考虑过在 ViewModel 中创建一个 RichTextBox 实例,并将 RichTextBox 绑定到 ViewModel 中的实例。我认为这违反了 MVVM,但我不完全确定。还有另一种方法可以解决这个问题吗?或者我应该只在 ViewModel 中创建 RichTextBox 实例吗?
例如: // 视图模型
RichTextBox Output;
// 更新方法
Output.AppendText(loggerInfoText);
// Xaml
<RichTextBox DataContext="{Binding Output}" />
提前致谢!
你像这样创建一个界面
interface IAppender{
void Append(string appendText);
}
您将此接口注入您的视图模型并在您的视图中实现它。 这意味着在您的视图模型代码中,您只需执行
appender.Append(loggerInfoText);
并且在您看来,您是通过向富文本添加文本来实现界面的。 根据视图和视图模型的实现,根据创建视图模型的位置,您可以在视图模型中注入接口。假设视图模型是在视图中创建的,您会得到如下内容:
class View : UserControl, IAppender{
View(){
InitializeComponent();
DataContext = new YourViewModel(this);
}
void Append(string appendText){
//add text to richttext
}
}
public class YourViewModel : ViewModelBase{
private IAppender _appender;
public YourViewModel(IAppender appender){
_appender = appender;
}
}
我希望这应该能让你入门 请注意,这是伪代码,甚至 运行 都没有通过编译器对其进行测试。 将 richttext 传递给 viewmodel 确实不是 MVVM。这个想法是分离关注点。通过我的界面方法,这没有被违反。
作为由您的控件实现的注入依赖项的替代方法(即使分离,也会使视图注入变得很痛苦):
首先,您可以在内部使用 StringBuilder 来构建您的字符串。
public class MyViewModel : ViewModelBase
{
private StringBuilder sb;
private string Content
{
return sb.ToString();
}
protected Append(string text) {
sb.Append(text);
PropertyChanged("Content");
}
}
然后将 Content
属性 绑定到您的 XAML 元素。这样你的 ViewModel 中就不会有 allocations/deallocations,你也不需要麻烦 DI 将你的 View/Control 注入 ViewModel(即使它是由接口抽象的)。
但是,这假设您要在任何地方都避免这种分配。如果您只想在某种类型的应用程序(即 Windows 商店应用程序)中使用它,而不是在您的 ASP.NET 或桌面应用程序中使用,则第二种选择可能更具吸引力(尤其是对于其他类似场景):
您可以使用自定义行为来实现此目的,如
并且它简化了您的 ViewModel,您将不必费心如何将实现 IAppender
的 View 注入到您的 ViewModel 中(这可能会在 View-first 方法中引起麻烦,其中 View 由IoC 并获取注入到视图中的 ViewModel 以设置为 DataContext)