How to create a common WPF base window style?

前端 未结 5 1306
一个人的身影
一个人的身影 2020-12-06 04:01

Is there any recommended way with WPF to create a common window style to be used across an application? I have several dialogs that appear in my app, and I would like them a

相关标签:
5条回答
  • 2020-12-06 04:03

    To add to H.B.'s very helpful post, you may want to connect your event handlers in the loaded event as he's done but instead of using anonymous methods or lambda expressions, consider connecting them to protected virtual methods which can be overridden in the derived class should the functionality need to vary. In my case, I created a base data entry form which has buttons for saving and cancelling:

        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) { }
    

    The save functionality is then overridden in each derived class to save the specific entity:

        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;
            }            
        }
    
    0 讨论(0)
  • 2020-12-06 04:08

    Create a Xaml Form template and add the template to the VS Installed ItemTemplates directory.

    1) create a wpf xaml and xaml.cs file that has all the desired components wanted for a new form added to your application. In my case I wanted the title and toolbar buttons.

    2) test the new xaml files through the current system flow.

    3) copy xaml / xaml.cs to temp location and rename both the filenames to something you want to be recognized as a good template name. a) Change first line within xaml file to -- Window x:Class="$rootnamespace$.$safeitemname$"

    b) Make 3 changes within xaml.cs file to ensure the new name will be copied when using the template - -- namespace $rootnamespace$ (//dynamic namespace name) -- public partial class $safeitemname$ (//dynamic class name) -- public $safeitemname$() (//dynamic constructor name)

    4) Now create a vstemplate file: ie. MyTemplate.vstemplate with the following content:

    <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) Once you have all these files, zip the files and place the zip file under the ....\Documents\Visual Studio 2012\Templates\ItemTemplates\WPF directory. Now you can go into VS2012 and use the ADD\New feature to see the template, select and rename as in the normal process. The template can be used in the same way for VS2010 by placing the zip file under the 2010 Templates Wpf directory.

    The Logo file should be included in the zip file as well or if you don't have a file then remove that line from the MyTemplate.vstemplate file.

    0 讨论(0)
  • 2020-12-06 04:16

    Creating a cusotm object , which is derived from Window Class..

    http://maffelu.net/wpf-window-inheritance-problems-and-problems/

    0 讨论(0)
  • 2020-12-06 04:22

    You can use define a style in App.Xaml that targets all windows.

    This is a sample of how your App.Xaml may look like:

    <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>
    

    Then for more advanced scenarios you may need to set the ControlTemplate for your Window.

    0 讨论(0)
  • 2020-12-06 04:23

    One way to do it would be a new custom control, let's call it DialogShell:

    namespace Test.Dialogs
    {
        public class DialogShell : Window
        {
            static DialogShell()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(DialogShell), new FrameworkPropertyMetadata(typeof(DialogShell)));
            }
        }
    }
    

    This now needs a template which would normally be defined in Themes/Generic.xaml, there you can create the default structure and bind the 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>
    

    This is just an example, you probably want to hook up those buttons with custom events and properties you need to define in the cs-file.

    This shell then can be used like this:

    <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();
            }
        }
    }
    

    Event wiring example (not sure if this is the "correct" approach though)

    <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;
                    };
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题