1

私は WPF を初めて使用しますが、このトピックに関する優れた本と、もちろん、このようなサイトの質の高い投稿のおかげで、短時間で多くの進歩を遂げることができました。しかし、今、それらの方法で理解できるように見えるものに出くわしたので、最初の質問を投稿します。

いくつかの UserControl ビューに適用するリソース ディクショナリに ControlTemplate があります。このテンプレートには、単純なオーバーレイ ボーダーと、[保存] と [キャンセル] の 2 つのボタンがあります。テンプレート化されたユーザー コントロールは、さまざまなテキスト ボックスなどを保持し、コンテキストに応じて一部の ViewModel にバインドされます。ビューで UserControl を使用/宣言するときに、コマンドを保存/キャンセル ボタンにバインドする方法を見つけようとしています。これは可能ですか、それとも私は何か非常に間違っていますか?

まず、テンプレート:

<ControlTemplate x:Key="OverlayEditorDialog"
                 TargetType="ContentControl">
    <Grid>
        <Border HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch"
                Background="DarkGray"
                Opacity=".7"/>
        <Border HorizontalAlignment="Center" 
                VerticalAlignment="Center"
                Background="DarkGray">
                <Grid>
                   <RowDefinition Height="Auto"/>
                    <RowDefinition/>
                </Grid.RowDefinitions>                    
                <ContentPresenter Grid.Row="0"/>                    
                <Grid Grid.Row="1" 
                      Margin="10">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <Button Grid.Column="1"
                            Content="Cancel"
                            ***Command="{Binding CancelCommand}}"**
                            />
                    <Button Grid.Column="0"
                            Content="Save"
                            ***Command="{Binding Path=SaveCommand}"***/>
                </Grid>
            </Grid>
        </Border>
    </Grid>
</ControlTemplate>

テンプレートは、CustomerEditorOverlay ユーザー コントロールで使用されます。

<UserControl x:Class="GarazhApp.View.CustomerEditorOverlay"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<UserControl.Resources>
    <ResourceDictionary Source="Dictionary1.xaml"/>
</UserControl.Resources>
<ContentControl Template="{StaticResource ResourceKey=OverlayEditorDialog}">        
    <Grid Grid.Row="0"
          HorizontalAlignment="Stretch"
          VerticalAlignment="Stretch">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>                
        </Grid.RowDefinitions>
        <SomeElement/>
        <SomeOtherElement/>
    </Grid>
</ContentControl>    

...そして最後に、ユーザー コントロールは次のようにビューの一部として使用されます。

<local:CustomerEditorOverlay Visibility="{Binding Path=CustomerViewModel.ViewMode, Converter={StaticResource myConverter}, FallbackValue=Collapsed}"
                                 d:IsHidden="True" />
4

1 に答える 1

4

というわけで、私がずっと半年間取り組んできたプロジェクトから学んだことに基づいて、実行可能なパターンができました。

アプリケーション内ですべて同じスタイルが適用される一連のモーダル ウィンドウがあるとします。各ビューに [保存] ボタンと [キャンセル] ボタンを表示するために、すべてのモーダル ウィンドウに使用される UserControl にはいくつかの依存関係プロパティがあります。さらに、コマンドの仮想メソッド (OnSaveCommand、OnCancelCommand、CanExecuteSaveCommand、CanExecuteCancelCommand など) とコマンド自体を、ビューに継承される基本 ViewModel のプロパティとして指定します。

最終的には、次のようにするだけで新しいモーダル ウィンドウを作成できます。

<my:YourBaseView x:class="MyFirstView" xmlns:whatever="whatever" [...]>
    <my:YourBaseView.PrimaryButton>
         <Button Content="Save" Command="{Binding SaveCommand}" />
    </my:YourBaseView.PrimaryButton>

    <!-- some content -->
</my:YourBaseView>

付属のコード ビハインドを使用:

public class MyFirstView : YourBaseView
{
    [Import] /* using MEF, but you can also do MvvmLight or whatever */
    public MyFirstViewModel ViewModel { /* based on datacontext */ }
}

そしてViewModel:

public class MyFirstViewModel : ViewModelBase
{
    public override OnSaveCommand(object commandParameter)
    {
        /* do something on save */
    }
}

この UserControl のテンプレートは、Content プロパティが PrimaryButton と SecondaryButton にバインドされたグリッド レイアウトで ContentControls を指定します。もちろん、モーダルのコンテンツは UserControl の Content プロパティに格納され、ContentPresenter にも表示されます。

<Style TargetType="{x:Type my:YourBaseView}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type my:YourBaseView}">
                <Grid>
                    <!-- ignoring layout stuff -->
                    <ContentControl Content="{TemplateBinding Content}" />
                    <ContentControl Content="{TemplateBinding PrimaryButton}" />
                    <ContentControl Content="{TemplateBinding SecondaryButton}" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

ユーザー コントロール コード:

public class YourBaseView : UserControl
{
    public static readonly DependencyProperty PrimaryButtonProperty =
        DependencyProperty.Register("PrimaryButton", typeof(Button), typeof(YourBaseView), new PropertyMetadata(null));
    public Button PrimaryButton
    {
        get { return (Button)GetValue(PrimaryButtonProperty); }
        set { SetValue(PrimaryButtonProperty, value); }
    }  

    /* and so on */
}

もちろん、テンプレート化されたビューのインスタンスごとにスタイルを変更できます。たまたま 1 つの基本スタイルに固執するだけです。

TL;DR 編集:新しいオーバーレイを作成するたびに、XAML を介して設定されるタイプ Button の依存関係プロパティを公開することを理解する必要があると思うので、少しやり過ぎたかもしれません。それか、おそらく RelativeSource を使用してビジュアル ツリーに戻ることもできますが{Binding DataContext.SaveCommand, RelativeSource={RelativeSource AncestorType={x:Type MyView}}}、少し汚いです。

于 2013-09-24T02:48:45.190 に答える