1

我是 WPF 的新手,但得益于一本关于该主题的好书,当然还有像这样的网站上的高质量帖子,我能够在短时间内取得很大进展。但是,现在我遇到了一些我似乎可以通过这些方式弄清楚的东西,所以我发布了我的第一个问题。

我在资源字典中有一个 ControlTemplate,我将其应用于多个 UserControl 视图。该模板提供了一个简单的覆盖边框和两个按钮:保存和取消。模板化的用户控件包含各种文本框等,并根据上下文绑定到某些 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 */ }
}

和一个视图模型:

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

此 UserControl 的模板在网格布局中指定 ContentControls,其中 Content 属性绑定到 PrimaryButton 和 SecondaryButton。当然,模式的内容存储在 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 */
}

当然,您可以更改模板视图的每个实例的样式。我们只是碰巧坚持一种基本风格。

TL;DR 编辑:我可能有点过火了,因为我认为您只需要了解每次创建新叠加层时都会通过 XAML 设置的 Button 类型的依赖项属性。那个,或者你可以用类似的方式回到可视化树中,{Binding DataContext.SaveCommand, RelativeSource={RelativeSource AncestorType={x:Type MyView}}}但它有点脏。

于 2013-09-24T02:48:45.190 回答