WPF绑定自定义输出窗口

时间:2009-11-24 18:12:33

标签: wpf data-binding xaml textbox

我正在尝试为绑定到ViewModel的软件创建自定义输出窗口。通常在过去我总是使用TextBox并使用appendText()方法写入输出窗口。当然,使用ViewModel并尝试绑定到文本框,您似乎只能绑定到Text属性。以下是我想要做的事情:

XAML:

<TextBox Text="{Binding Output}"></TextBox>

C#

public class ViewModel : DependencyObject
    {
        public static readonly DependencyProperty OutputProperty = DependencyProperty.Register("Output", typeof(ObservableCollection<string>), typeof(MVVMTestViewModel), new UIPropertyMetadata(null));

        public ObservableCollection<string> Output
        {
            get
            {
                return (ObservableCollection<string>)GetValue(OutputProperty);
            }
            set
            {
                SetValue(OutputProperty, value);
            }
        }

        public ViewModel()
        {
            Output = new ObservableCollection<string>();
        }

        public void OutputMessage(string message)
        {
            Output.Add(message);
        }
    }

当然这是不可能的,因为Text无法分配给Observable Collection。

注意:我可以使用ListView或ListBox并使用可观察的集合。但我不喜欢选择模式。我希望能够突出显示TextBox的文本,以便我可以将其复制并粘贴到Window之外。 isReadOnly属性允许我相当容易地做到这一点。

有一种简单的方法吗?另一个控制我可能没有?

2 个答案:

答案 0 :(得分:4)

我认为托马斯所说的是你可以在你的Window的代码隐藏中拥有以下内容:

public partial class MyWindow : Window
{
    ViewModel _vm;

    public MyWindow(ViewModel vm)
    {
        InitializeComponent();
        _vm = vm;
        _vm.Output.CollectionChanged += Output_CollectionChanged;
    }

    void Output_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        foreach(object item in e.NewItems)
        {
            outputTextBox.AppendText(item.ToString());
        }
    }
}

这样,窗口类将自动附加添加到Output集合的任何文本。

另一种方法(虽然它可能不被视为纯MVVM)是通过使用如下接口:

public interface IAppendOutput
{
    void Append(string text);
}

public partial class MyWindow : Window, IAppendOutput
{
    public MyWindow()
    {
        InitializeComponent();
    }

    public void Append(string text)
    {
        outputTextBox.AppendText(text);
    }
}

public class ViewModel
{
    IAppendOutput _outputter;
    public ViewModel(IAppendOutput outputter)
    {
        _outputter = outputter;
    }

    public void AppendOutput(string text)
    {
        _outputter.Append(text);
    }
}

然后在你的主应用程序中:

...
MyWindow window = new MyWindow();
ViewModel vm = new ViewModel(window);
window.DataContext = vm;
window.Show();
vm.AppendOutput("This is a test.");
...

这种方式可能不是最好的方法,但它可能是一种在其他情况下编写快速管道磁带代码的有用方法。它仍然是单元可测试的,因为ViewModel不了解窗口本身,只知道接口。它仍然是灵活的,因为您可以自定义任何类型的对象,以便它实现IAppendOutput接口。

答案 1 :(得分:1)

您可以使用转换器将集合转换为字符串:

public class ListToStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        IEnumerable lst = value as IEnumerable;
        if (lst != null)
        {
            StringBuilder sb = new StringBuilder();
            foreach(var item in lst)
            {
                sb.AppendLine(item.ToString());
            }
            return sb.ToString();
        }
        return null;
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }

}