在viewmodel中创建控件实例

时间:2015-02-09 20:11:54

标签: c# wpf mvvm richtextbox viewmodel

在我的程序中,我正在尝试设计一个输出窗口来显示日志记录信息。现在,我正在绑定一个字符串,并在日志数据进入后立即更新信息。

前:

<FlowDocument>
    <Paragraph>
        <Run DataContext="{Binding}" Text="{Binding OutputText}"/>
    </Paragraph>
</FlowDocument>

(流文档位于富文本框内)

在我的viewmodel中,这就是我更新输出文本的方式

OutputText += loggingInfoString; 

问题是字符串是不可变的数据类型,我不喜欢每次新数据进入时创建新字符串的想法。这是一个不必要的开销。

RichTextBox有一个名为AppendText的方法,我假设它会使用类似Stringbuilder的东西来添加到字符串中。我遇到的问题是能够访问ViewModel中的AppendText。

我考虑过在ViewModel中创建一个RichTextBox实例,并将RichTextBox绑定到ViewModel中的一个。我认为这违反了MVVM,但我并不完全确定。还有另一种方法可以解决这个问题吗?或者我应该在ViewModel中创建RichTextBox实例吗?

例: // ViewModel

RichTextBox Output;

//更新方法

Output.AppendText(loggerInfoText);

// Xaml

<RichTextBox DataContext="{Binding Output}" />

提前致谢!

2 个答案:

答案 0 :(得分:2)

您可以创建一个类似的界面

interface IAppender{
    void Append(string appendText);
}

您将此接口注入到viewmodel中,然后在视图中实现它。 这意味着您只需在viewmodel代码中执行

appender.Append(loggerInfoText);

在您的视图中,您通过向richtext添加文本来实现界面。 基于view和viewmodel的实现,根据viewmodel的创建位置,您可以在viewmodel中注入接口。假设在视图中创建了viewmodel,你得到这样的东西:

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。我们的想法是分离关注点。通过我的界面方法,这不会被违反。

答案 1 :(得分:-1)

作为注入依赖项的替代方法(即使解耦,使得视图中的注入令人痛苦),这是由您的控件实现的:

首先,您可以在内部使用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中进行分配/解除分配,并且您不需要麻烦地将DI注入ViewModel(即使它被接口抽象)。

但是,这假设您将在任何地方避免这种分配。如果您只想在某种类型的应用程序(即Windows应用商店应用程序)中使用它,而不是在ASP.NET或桌面应用程序中,则第二种替代方案可能更具吸引力(特别是对于其他类似方案):

您可以使用自定义行为来实现此目标,如this question中的答案所示。行为是可重用的,您无需在ViewModel中执行此类决策,从而允许您针对每个平台甚至每个View进行不同的处理。

它简化了您的ViewModel,您不必费心如何将实现IAppender的View注入ViewModel(可能会导致View-first方法出现问题,其中View由IoC解决)并将ViewModel注入View中设置为DataContext)