我正在使用this article和其他资源慢慢学习WPF。
我专注于应用程序逻辑 - 定义模型+ viewModel,并创建对这些操作进行操作的命令。我还没有查看视图和.xaml
格式。
当我在处理逻辑时,我希望有一个视图可以渲染我绑定到它的任何viewModel。视图应该
string
属性渲染为文本框,并将文本框绑定到属性维护MVVM设计模式时是否可以这样?如果是这样,我将如何实现它?此外,文章建议避免使用.xaml
代码隐藏 - 此视图是否可以在纯xaml中实现?
答案 0 :(得分:6)
我认为只有XAML才有可能。如果要在运行时生成视图,则必须在ViewModel上使用反射并相应地生成控件。如果要在编译时生成视图,则可以在构建时使用某些模板引擎(如T4或字符串模板)或CodeDom从ViewModel生成xaml文件。或者你可以更进一步,有一些元数据格式(甚至DSL),你将从中生成模型和视图等。这取决于您的应用需求。
同样在MVVM中,代码隐藏对于视觉逻辑和对模型/视图模型的绑定是好的,这些只能在XAML中完成。
答案 1 :(得分:3)
我不确定这是否适用于“纯MVVM”方法,当然不是所有内容都只是通过绑定来实现。而且我只是抛弃了避免在这里使用代码隐藏的想法,这是一个固有的程序化任务。你应该坚持的一件事是让ViewModel不了解视图,所以当你用“真实的东西”替换它时,没有工作可做。
但肯定看起来合情合理;它几乎听起来更像是一个调试可视化工具 - 你可以利用现有的工具来实现这一点。
(如果您确实希望在大多数XAML中使用标准ItemsControl
和模板执行此操作,您可以编写转换器以通过以可以绑定的某种形式的反射来公开ViewModel的属性,这是一个包装器的集合具有公开元数据的对象,但我认为确保公开的属性是正确可绑定的,这将是更多的工作而不是它的价值)
答案 2 :(得分:3)
我现在正在执行此操作的一半,我希望以下代码可以帮助其他人尝试这样做。变成一个更强大的库可能会很有趣。
AbstractView.xaml
:
<UserControl x:Class="MyApplication.View.AbstractView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel Name="container">
</StackPanel>
</UserControl>
AbstractView.xaml.cs
:
public partial class AbstractView : UserControl
{
public AbstractView()
{
InitializeComponent();
DataContextChanged += Changed;
}
void Changed(object sender, DependencyPropertyChangedEventArgs e)
{
object ob = e.NewValue;
var props = ob.GetType().GetProperties();
List<UIElement> uies = new List<UIElement>();
foreach (var prop in props)
{
if (prop.PropertyType == typeof(String))
uies.Add(makeStringProperty(prop));
else if (prop.PropertyType == typeof(int))
uies.Add(makeIntProperty(prop));
else if (prop.PropertyType == typeof(bool))
uies.Add(makeBoolProperty(prop));
else if (prop.PropertyType == typeof(ICommand))
uies.Add(makeCommandProperty(prop));
else
{
}
}
StackPanel st = new StackPanel();
st.Orientation = Orientation.Horizontal;
st.HorizontalAlignment = HorizontalAlignment.Center;
st.Margin = new Thickness(0, 20, 0, 0);
foreach (var uie in uies) {
if (uie is Button)
st.Children.Add(uie);
else
container.Children.Add(uie);
}
if (st.Children.Count > 0)
container.Children.Add(st);
}
UIElement makeCommandProperty(PropertyInfo prop)
{
var btn = new Button();
btn.Content = prop.Name;
var bn = new Binding(prop.Name);
btn.SetBinding(Button.CommandProperty, bn);
return btn;
}
UIElement makeBoolProperty(PropertyInfo prop)
{
CheckBox bx = new CheckBox();
bx.SetBinding(CheckBox.IsCheckedProperty, getBinding(prop));
if (!prop.CanWrite)
bx.IsEnabled = false;
return makeUniformGrid(bx, prop);
}
UIElement makeStringProperty(PropertyInfo prop)
{
TextBox bx = new TextBox();
bx.SetBinding(TextBox.TextProperty, getBinding(prop));
if (!prop.CanWrite)
bx.IsEnabled = false;
return makeUniformGrid(bx, prop);
}
UIElement makeIntProperty(PropertyInfo prop)
{
TextBlock bl = new TextBlock();
bl.SetBinding(TextBlock.TextProperty, getBinding(prop));
return makeUniformGrid(bl, prop);
}
UIElement makeUniformGrid(UIElement ctrl, PropertyInfo prop)
{
Label lb = new Label();
lb.Content = prop.Name;
UniformGrid u = new UniformGrid();
u.Rows = 1;
u.Columns = 2;
u.Children.Add(lb);
u.Children.Add(ctrl);
return u;
}
Binding getBinding(PropertyInfo prop)
{
var bn = new Binding(prop.Name);
if (prop.CanRead && prop.CanWrite)
bn.Mode = BindingMode.TwoWay;
else if (prop.CanRead)
bn.Mode = BindingMode.OneWay;
else if (prop.CanWrite)
bn.Mode = BindingMode.OneWayToSource;
return bn;
}
}
答案 3 :(得分:1)
指针:生成动态DataTemplate作为绑定到特定VM(目标)的字符串。通过XamlReader解析它。将其插入代码中的应用程序资源。
只是一个想法..用它运行..应该通过View或ViewModel以外的某种类型来完成。