如何重用WPF客户窗口

时间:2017-10-18 07:03:32

标签: c# wpf xaml

我创建了自定义窗口(标题栏,最小/最大/外部按钮,自己的窗口操作边框以及许多样式和触发器)。

定义了5种方法(我想覆盖):

从窗口标记:

SourceInitialized="Window_SourceInitialized"

Closing="Window_Closing"

从标题栏按钮:

Exit_Click()

Max_Click()

Min_Click()

最后我有DockPanel

<DockPanel Name="ClientArea"/>

我想把我的内容放在哪里

我尝试过添加代码中的内容:

BaseWindow editInterfaceWindow = new BaseWindow() { Owner = this };                  
editInterfaceWindow.DataContext = new EditInterface();
editInterfaceWindow.ShowDialog();

但是这样一些绑定停止工作并且在editInterfaceWindow里面我因为Owner = this而无法以这种方式创建另一个窗口。构造函数中InitializeComponent()也存在一些问题。 EditInterface UserControl <ListView Name="LBAvaliable" ItemsSource="{Binding AvaliableFaces, UpdateSourceTrigger=PropertyChanged}">中的ListView在代码中不可见为LBAvaliable。

我几次使用该窗口,手动填写ClientArea内容。 我应该如何创建其他窗口,以便我可以继承它或只定义绑定?所以我的每个窗口的XAML都不需要大约1000行代码。

2 个答案:

答案 0 :(得分:1)

过去我曾使用MVVMCross Framework而我们自己也不必为此担心。虽然这不是最好的,但这里有一个关于你能做什么的想法。

  1. 创建一个可以为用户控件覆盖的视图模型。
  2. 设置数据模板。
  3. 以编程方式更改用户控件主要内容的视图模型,并让数据模板为UI工作。
  4. 查看模型:预定义的3个按钮操作可供您设置/覆盖。

    public class MainUCViewModel : ViewModelBase
    {
        private Action<object> btnACommand;
        private Action<object> btnBCommand;
        private Action<object> btnCCommand;
    
        private object ccVM;
    
        public ViewModelBase CCVM
        {
            get { return this.ccVM; }
            set
            {
                this.ccVM = value;
                OnPropertyChanged(); // Notify View
            }
        }
    
        public MainUCViewModel()
        {
    
        }
    
        public RelayCommand BtnACommand
        {
            get { return new RelayCommand(btnACommand); }
        }
    
        public RelayCommand BtnBCommand
        {
            get { return new RelayCommand(btnBCommand); }
        }
    
        public RelayCommand BtnCCommand
        {
            get { return new RelayCommand(btnCCommand); }
        }
    
        public void SetBtnACommand(Action<object> action)
        {
            this.btnACommand = action;
        }
    
        public void SetBtnBCommand(Action<object> action)
        {
            this.btnBCommand = action;
        }
    
        public void SetBtnCCommand(Action<object> action)
        {
            this.btnCCommand = action;
        }
    } 
    

    查看:

    <UserControl x:Class="WpfApplication1.Views.UserControls.MainUC"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 d:DesignHeight="500" d:DesignWidth="750">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="45" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Grid Grid.Row="0">
                <StackPanel Orientation="Horizontal">
                    <Button Command="{Binding BtnACommand}" Width="100">
                        <TextBlock>A</TextBlock>
                    </Button>
                    <Rectangle Width="15" />
                    <Button Command="{Binding BtnBCommand}" Width="100">
                        <TextBlock>B</TextBlock>
                    </Button>
                    <Rectangle Width="15" />
                    <Button Command="{Binding BtnCCommand}" Width="100">
                        <TextBlock>C</TextBlock>
                    </Button>
                </StackPanel>
            </Grid>
            <Grid Grid.Row="1">
                <ContentControl x:Name="CCMain" Content="{Binding CCVM}"/>
            </Grid>
        </Grid>
    </UserControl>
    

    看看Thinking with MVVM: Data Templates + ContentControl。只需为视图模型定义数据模板即可。

    <Window.Resources>
        <DataTemplate DataType="{x:Type ViewModel:GeneralSettingsViewModel}">
            <View:GeneralSettingsView/>
        </DataTemplate
        <DataTemplate DataType="{x:Type ViewModel:AdvancedSettingsViewModel}">
            <View:AdvancedSettingsView/>
        </DataTemplate>
    </Window.Resources>   
    
      

    我在这里说的是GeneralSettingsViewModel应该是   使用GeneralSettingsView呈现。这正是我们所需要的!   因为视图是使用DataTemplate创建的,所以我们不需要   设置DataContext,它会自动注册到   模板化对象,ViewModel。

答案 1 :(得分:0)

您的问题有两种主要方法:

  1. 继承的窗口
  2. 可配置的窗口
  3. 对于方法1,设计窗口并使方法可重写:

    在基本窗口xaml中,分配处理程序和所需的一切:

    <Window x:Class="WpfTests.MainWindow"
        ...
        SourceInitialized="Window_SourceInitialized">
    

    在基本窗口中,将处理程序定义为protected virtual(或abstract,如果您想强制执行它们的话)

    public partial class MainWindow : Window
    {
        // ...
    
        protected virtual void Window_SourceInitialized(object sender, EventArgs e)
        {
    
        }
    
        // ...
    }
    

    创建派生窗口

    public class ExWindow : MainWindow
    {
        protected override void Window_SourceInitialized(object sender, EventArgs e)
        {
            // specialized code here
        }
    }
    

    将App.xaml更改为使用Startup而不是StartupUri

    <Application x:Class="WpfTests.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Startup="Application_Startup">
    

    手动创建第一个窗口,选择一个继承的窗口类

    public partial class App : Application
    {
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            var window = new ExWindow();
            window.Show();
        }
    }
    

    第二种方法 - 可配置窗口 - 遵循与良好用户控件设计相同的原则:窗口/控件属性由创建者控制,而不是由窗口/控件本身控制。

    因此,不要在窗口代码中定义一些事件处理程序,只需将此练习留给用户,用户希望知道窗口应该做什么:

    public partial class MainWindow : Window
    {
        // I don't care for SourceInitialized (also remove it from XAML)
    }
    

    在App.xaml中或创建窗口的任何地方:

    public partial class App : Application
    {
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            var window = new MainWindow();
            window.SourceInitialized += window_SourceInitialized;
            window.Show();
        }
    
        void window_SourceInitialized(object sender, EventArgs e)
        {
            var window = sender as MainWindow;
    
            // I know how to handle this event for this window instance
        }
    }