参数仅在使用ContentControl时为空

本文关键字:ContentControl 参数 | 更新日期: 2023-09-27 18:06:24

我正在为使用WPF的应用程序开发UI。我正在使用命令绑定。当按钮放在窗口内时,命令正常工作。但是当我把按钮放在UserControl里面的时候,命令参数是空的。

ViewModel代码:

        public RelayCommand<Window> MainCommand { get; private set; }
        private void MainAction(Window window)
        {
            // here the parameter is null
            if (window == null) return;
            MainPage main = new MainPage();
            main.Show();
            window.Close();
        }

用户控件:

    <UserControl x:Class="Kitchen.UI.View.HeaderFooter"
                 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" 
                 xmlns:local="clr-namespace:Kitchen.UI.View"
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
        <UserControl.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="../Skins/MainSkin.xaml"/>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </UserControl.Resources>
        <UserControl.Template>
            <ControlTemplate TargetType="UserControl">
                <Grid DataContext="{Binding DataContext, RelativeSource={RelativeSource TemplatedParent}}">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="*"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                        <ColumnDefinition Width="Auto"></ColumnDefinition>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <ScrollViewer Grid.Column="1" Grid.Row="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
                        <ContentControl Content="{TemplateBinding Content}"/>
                    </ScrollViewer>
                    <Image Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3" Source="{StaticResource HeaderImage}"
                   Margin="0 10 0 0" HorizontalAlignment="Stretch" SizeChanged="Image_SizeChanged" IsHitTestVisible="False"></Image>
                    <Image Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="3" Source="{StaticResource FooterImage}"
                   Margin="0 -1 0 10" HorizontalAlignment="Stretch"  Height="Auto"></Image>

                </Grid>
            </ControlTemplate>
        </UserControl.Template>
    </UserControl>

我将按钮放入用户控件的方式:

<Window xmlns:View="clr-namespace:Kitchen.UI.View"  x:Class="Kitchen.UI.View.Order" Name="OWindow"  ResizeMode="NoResize" WindowState="Maximized"
        WindowStartupLocation="CenterOwner" WindowStyle="None "
        Width="1600"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:ignore="http://www.galasoft.ch/ignore"
        mc:Ignorable="d ignore" 
        DataContext="{Binding Order, Source={StaticResource Locator}}">

    <View:HeaderFooter x:Name="HeaderFooter">
        <Button Grid.Row="1" Grid.Column="0" 
                Command="{Binding ShowExitCommand}"
                        CommandParameter="{Binding ElementName=OWindow}"
                Style="{StaticResource ImageButtonStyle}">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition ></RowDefinition>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <Image Grid.Column="0" Grid.Row="0" Source="{StaticResource ButtonBack}" Width="180" Grid.ColumnSpan="2" />
                    <TextBlock Grid.Column="1" Grid.Row="0" Text="مشاهده سفارشات خارج شده از صف" Style="{StaticResource ImageButtonTextBlockStyle}" FontSize="15"/>
                </Grid>
        </Button>
    </View:HeaderFooter>
</Window>

参数仅在使用ContentControl时为空

尝试用x:Reference代替ElementName,这个应该带来对元素引用解析的语言级支持,而ElementName(在框架级操作)可能无法解析。

CommandParameter="{Binding Source={x:Reference OWindow}}"

为了避免循环依赖,你必须引用一些不是用户控件本身容器的东西,例如

<Grid >
    <DataGrid  Name="OWindow" Width="10" Height="10"/>
    <local:HeaderFooter x:Name="HeaderFooter">
    <Button Grid.Row="1" Grid.Column="0" 
            Command="{Binding ShowExitCommand}"
                    CommandParameter="{Binding  Source={x:Reference OWindow} }" 
            > <!-- instead of ElementName=OWindow   -->

请注意,上面的例子清楚地表明我的答案在一致的上下文中正确地解决了问题,而循环引用只是原始代码的另一个问题。

最后我改变了解决问题的方法。我需要一个模板应用于几个窗口,所以我使用了UserControl,它作为模板是成功的,除非我想将UserControl的包含窗口的引用作为参数传递给UserControl内容中的命令。

现在我正在应用一个自定义的ControlTemplate到窗口,它现在正在工作。

但是我认为这是WPF的一个bug,或者至少是一个架构上的弱点。当你在窗口本身或其他控件(如Grid)中使用{Binding ElementName=OWindow}时,引用被解析和处理,但如果你在用户定义的用户控件中使用它,它会导致空引用。

我认为这是因为它们在Window构造中捕获了参数。