我是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" />
答案 0 :(得分: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的模板在网格布局中指定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>
UserControl代码:
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}}}
的方式将你的方式重新连接到视觉树上,但它有点脏。