7

この記事やその他のリソースを使用して、WPFを徐々に学習しています。

私はアプリケーションロジックに焦点を当てています-モデル+viewModelを定義し、これらを操作するコマンドを作成します。.xamlビューとフォーマットはまだ見ていません。

ロジックに取り組んでいる間、バインドした任意のviewModelをレンダリングできるビューが必要です。ビューは

  • パブリックプロパティをテキストボックスとしてレンダリングしstring、テキストボックスをプロパティにバインドします
  • プロパティの名前をラベルとしてレンダリングします。
  • public'Command'プロパティをボタンとしてレンダリングし、ボタンをコマンドにバインドします(おそらく、コマンドが引数をとらない場合のみ?)

MVVMデザインパターンを維持しながら、このようなことは可能ですか?もしそうなら、私はそれをどのように達成しますか?また、この記事では、コードビハインドの使用を避けることを提案してい.xamlます-このビューは純粋なxamlで実装できますか?

4

4 に答える 4

6

XAMLだけでは不可能だと思います。実行時にビューを生成する場合は、ViewModelでリフレクションを使用し、それに応じてコントロールを生成する必要があります。コンパイル時にビューを生成する場合は、ビルド時にViewModelsからテンプレートエンジン(T4や文字列テンプレートなど)またはCodeDomを使用してxamlファイルを生成できます。または、さらに進んで、モデルとビューなどの両方を生成するメタデータ形式(またはDSL)を使用することもできます。それはあなたのアプリのニーズ次第です。

また、MVVMのコードビハインドでは、XAMLだけでは実行できないビジュアルロジックとモデル/ビューモデルへのバインドが可能です。

于 2012-04-13T11:33:42.520 に答える
3

これが「純粋なMVVM」アプローチの適切な使用法であるかどうかはわかりません。確かに、バインドするだけですべてが達成されるわけではありません。そして、ここでの「ビュー」にコードビハインドを使用しないという考えを捨てるだけです。これは本質的にプログラム的なタスクです。固執する必要がある1つのことは、ViewModelにビューの知識を与えないことです。これにより、ビューを「本物」に置き換えるときに、実行する作業がなくなります。

しかし、確かに合理的なことのようです。デバッグビジュアライザーのように聞こえます。既存のツールを利用できる場合があります。

(標準のテンプレートを使用するほとんどのXAMLでこれを実行したい場合はItemsControl、バインド可能な何らかの形式でのリフレクションによってViewModelのプロパティを公開するコンバーター、公開されたメタデータを含むラッパーオブジェクトのコレクションを作成できますが、公開されたプロパティが適切にバインド可能であることを確認することは、価値があるよりも多くの作業になります)

于 2012-04-13T11:40:34.827 に答える
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;
    }

}
于 2012-04-13T13:54:03.960 に答える
1

ポインター:特定のVM(ターゲット)に関連付けられた文字列として動的DataTemplateを生成します。XamlReaderを介して解析します。コードでアプリリソースに追加します。

ただのアイデア..それを使って実行する..ViewまたはViewModel以外のタイプで実行する必要があります。

于 2012-04-13T12:39:17.363 に答える