我知道如何制作基本的.cs用户控件文件,但是我无法想出一种好的方法来创建一个可以在启动时承载不同内容的单个窗口?
谢谢, rJ
有一种方法是创建一个新的自定义控件,让我们称其为DialogShell
:
namespace Test.Dialogs
{
public class DialogShell : Window
{
static DialogShell()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DialogShell), new FrameworkPropertyMetadata(typeof(DialogShell)));
}
}
}
现在需要一个模板,通常应该在Themes/Generic.xaml
中定义,你可以在那里创建默认的结构并绑定Content
:
这句话意思是,需要创建一个模板来定义一个控件的外观和行为,模板通常会在Themes/Generic.xaml
文件中定义。你可以在模板中定义控件的默认结构,并将Content
属性与其它控件或数据进行绑定。
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Test.Dialogs">
<Style TargetType="{x:Type local:DialogShell}" BasedOn="{StaticResource {x:Type Window}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:DialogShell}">
<Grid Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- This ContentPresenter automatically binds to the Content of the Window -->
<ContentPresenter />
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="5" HorizontalAlignment="Right">
<Button Width="100" Content="OK" IsDefault="True" />
<Button Width="100" Content="Cancel" IsCancel="True" />
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
这只是一个例子,您可能希望将这些按钮与您在cs文件中定义的自定义事件和属性进行连接。
然后可以像这样使用此 shell:
<diag:DialogShell x:Class="Test.Dialogs.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:diag="clr-namespace:Test.Dialogs"
Title="Window1" Height="300" Width="300">
<Grid>
<TextBlock Text="Lorem Ipsum" />
</Grid>
</diag:DialogShell>
namespace Test.Dialogs
{
public partial class Window1 : DialogShell
{
public Window1()
{
InitializeComponent();
}
}
}
事件绑定示例(不确定这是否是“正确”的方法)<Button Name="PART_OKButton" Width="100" Content="OK" IsDefault="True" />
<Button Name="PART_CancelButton" Width="100" Content="Cancel" IsCancel="True" />
namespace Test.Dialogs
{
[TemplatePart(Name = "PART_OKButton", Type = typeof(Button))]
[TemplatePart(Name = "PART_CancelButton", Type = typeof(Button))]
public class DialogShell : Window
{
//...
public DialogShell()
{
Loaded += (_, __) =>
{
var okButton = (Button)Template.FindName("PART_OKButton", this);
var cancelButton = (Button)Template.FindName("PART_CancelButton", this);
okButton.Click += (s, e) => DialogResult = true;
cancelButton.Click += (s, e) => DialogResult = false;
};
}
}
}
补充H.B.非常有帮助的帖子,您可能希望像他一样在已加载的事件中连接事件处理程序,但不要使用匿名方法或lambda表达式,考虑将它们连接到受保护的虚拟方法中,如果功能需要变化,则可以在派生类中重写它们。在我的情况下,我创建了一个基本的数据输入表单,其中包含保存和取消按钮:
public DataEntryBase()
{
Loaded += (_, __) =>
{
var saveButton = (Button)Template.FindName("PART_SaveAndCloseButton", this);
var cancelButton = (Button)Template.FindName("PART_CancelButton", this);
saveButton.Click += SaveAndClose_Click;
cancelButton.Click += Cancel_Click;
};
}
protected virtual void SaveAndClose_Click(object sender, RoutedEventArgs e) { DialogResult = true; }
protected virtual void Cancel_Click(object sender, RoutedEventArgs e) { }
protected override void SaveAndClose_Click(object sender, RoutedEventArgs e)
{
if (Save())
{
base.SaveAndClose_Click(sender, e);
}
}
private bool Save()
{
Contact item = contactController.SaveAndReturnContact((Contact)DataContext);
if (item!=null)
{
DataContext = item;
return true; }
else
{
MessageBox.Show("The contact was not saved, something bad happened :(");
return false;
}
}
Close()
是多余的,设置 DialogResult
就可以关闭窗口了。 - H.B.你可以在 App.Xaml 中定义一个针对所有窗口的样式。
下面是一个 App.Xaml 的示例:
<Application x:Class="ES.UX.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Views/MainWindow.xaml">
<Application.Resources>
<Style TargetType="Window">
<Setter Property="WindowStyle" Value="ToolWindow" />
</Style>
</Application.Resources>
对于更高级的场景,您可能需要为窗口设置ControlTemplate。
创建一个Xaml表单模板并将其添加到VS安装的ItemTemplates目录中。
1)创建一个WPF Xaml和Xaml.cs文件,其中包含您想要添加到应用程序中的新表单所需的所有组件。在我的情况下,我想要标题和工具栏按钮。
2)通过当前系统流程测试新的xaml文件。
3)将xaml / xaml.cs复制到临时位置,并将两个文件名重命名为您想要识别为良好模板名称的内容。 a)更改xaml文件中的第一行为 - Window x:Class =“$ rootnamespace $。$ safeitemname $”
b)在xaml.cs文件中进行3个更改,以确保在使用模板时将复制新名称 - -- namespace $rootnamespace$ (//动态命名空间名称) -- public partial class $safeitemname$ (//动态类名) -- public $safeitemname$() (//动态构造函数名称)
4)现在创建一个vstemplate文件:即MyTemplate.vstemplate,其中包含以下内容:
<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="Item">
<TemplateData>
<DefaultName>WpfFormTemplate.xaml</DefaultName>
<Name>WpfFormTemplate</Name>
<Description>Wpf/Entities form</Description>
<ProjectType>CSharp</ProjectType>
<SortOrder>10</SortOrder>
<Icon>Logo.ico</Icon>
</TemplateData>
<TemplateContent>
<References>
<Reference>
<Assembly>System.Windows.Forms</Assembly>
</Reference>
<Reference>
<Assembly>Workplace.Data.EntitiesModel</Assembly>
</Reference>
<Reference>
<Assembly>Workplace.Forms.MainFormAssemb</Assembly>
</Reference>
</References>
<ProjectItem SubType="Designer" TargetFileName="$fileinputname$.xaml" ReplaceParameters="true">WpfFormTemplate.xaml</ProjectItem>
<ProjectItem SubType="Code" TargetFileName="$fileinputname$.xaml.cs" ReplaceParameters="true">WpfFormTemplate.xaml.cs</ProjectItem>
</TemplateContent>
</VSTemplate>
5) 一旦您拥有了所有这些文件,请将它们压缩并将压缩文件放置在....\Documents\Visual Studio 2012\Templates\ItemTemplates\WPF目录下。现在,您可以进入VS2012并使用ADD\New功能查看模板,选择并重命名,就像正常流程一样。通过将zip文件放置在2010 Templates Wpf目录下,也可以以同样的方式在VS2010中使用该模板。
Logo文件也应包含在zip文件中,如果没有该文件,则从MyTemplate.vstemplate文件中删除该行。
http://maffelu.net/wpf-window-inheritance-problems-and-problems/
Loaded
事件可行)。如果只有OK和Cancel,您可能甚至不想公开这些按钮的事件,因为它们应该只将DialogResult
设置为true或false。(如果您这样做,请将这些按钮作为template-parts,以便创建主题的人知道按钮应该如何命名) - H.B.<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
- H.B.