Window和UserControl在Designer中不同步

时间:2018-07-26 20:06:38

标签: c# wpf xaml user-controls window

我目前正在尝试将.xaml文件拆分为多个.xaml文件,因此我选择创建一些UserControl。

首先,如果我运行该项目,我的代码可以正常工作,只有设计者无法正确显示我的UI,但是如果没有所有自定义创建的UserControl,在MainWindow.xaml中包含所有内容之前,它都可以正常工作。

让我描述一下不当行为。我没有视图,请先选择并选择我的MainWindow.xaml。从理论上讲,一切都很好。现在,我打开InformationTabItemsUserControl.xaml,然后单击第二个TabItem。在那里工作正常。使用属性IsSelected设置第二个条目。 现在,我再次切换回包含UserControl的MainWindow.xaml,现在每个项目的可见性检查都失败了,就好像之前没有选择TabItem一样。

要进行检查,我在InformationTabItemsUserControl中创建了SelectedIndex依赖项属性,并通过SelectedIndex =“ 1”在MainWindow.xaml中将其设置为UserControl元素。现在,我重新编译了该项目,重新启动了Visual Studio,但没有进行任何更改,所选的TabItem再次成为第一个。在该UserControl的属性中,我看到SelectedIndex为0,但XAML代码将其指定为1。现在,如果我在属性中手动设置它,则XAML不会更改,但现在会显示正确的TabItem。

另一种尝试是使用ValueConverter和Debugger.Break在绑定中检查UserControl的对象。因此,我附加了另一个Visual Studio实例并打开MainWindow.xaml。 ValueConverter被执行,我通过调用GetHashCode()收到了UserControl的哈希。现在,我再次切换到InformationTabItemsUserControl.xaml,然后又回到MainWindow.xaml。某种程度上,UserControl的GetHashCode()发生了变化,所以我认为该对象已重新创建,现在我有了一些不正确的绑定。

但是正如我所说的,它仅在Designer中发生。运行正常。希望你能理解我的问题。预先感谢。

我缩小了MainWindow.xaml

<Controls:MetroWindow
                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                  xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
                  xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
                  xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
                  xmlns:sn="clr-namespace:Launcher.Controls.Custom"
                  xmlns:wpf="clr-namespace:TheArtOfDev.HtmlRenderer.WPF;assembly=HtmlRenderer.WPF"
                  xmlns:data="clr-namespace:Launcher.Data"
                  xmlns:class="clr-namespace:Launcher.Class"
                  xmlns:controlProps="clr-namespace:Launcher.ControlProps"
                  xmlns:converter="clr-namespace:Launcher.Class.Converter"
                  xmlns:views="clr-namespace:Launcher.Views"
                  xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=PresentationFramework"
                  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                  xmlns:lex="http://wpflocalizeextension.codeplex.com"
                  xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
                  xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
                  xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
                  xmlns:local="clr-namespace:HtmlToXamlConvert"
                  xmlns:behaviour="clr-namespace:Launcher.Behaviour"
                  xmlns:componentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
                  xmlns:Launcher="clr-namespace:Launcher" x:Class="Launcher.Views.MainWindow"
                  x:Name="Main"
                  mc:Ignorable="d"
                  lex:LocalizeDictionary.DesignCulture="en"
                  lex:LocalizeDictionary.OutputMissingKeys="True"
                  lex:ResxLocalizationProvider.DefaultAssembly="Launcher"
                  lex:ResxLocalizationProvider.DefaultDictionary="Resources"
                  ShowTitleBar="True"
                  ShowIconOnTitleBar="True"
                  TitlebarHeight="50"
                  WindowStartupLocation="CenterScreen"
                  Closing="OnClose" 
                  StateChanged="OnStateChanged" 
                  IsVisibleChanged="OnIsVisibleChanged"
                  d:DataContext="{d:DesignInstance IsDesignTimeCreatable=True, Type={x:Type views:MainWindow}}"
                  Title="{lex:Loc Key=MainWindow.MainTitle}"
                  Height="720"
                  Width="1024"
                  MinHeight="720"
                  MinWidth="1024" Loaded="MetroWindow_Loaded">

                  <Grid x:Name="InformationTabItems" Panel.ZIndex="0" Margin="0,0,0,0">
                    <Rectangle Fill="{StaticResource PrimaryBackgroundBrush}" Stretch="Fill" />
                    <Rectangle Height="1" Margin="0,0,0,0" Fill="#FF000000" VerticalAlignment="Top" />
                    <Rectangle Height="1" Margin="0,1,0,0" Fill="{StaticResource DarkSeperatorBrush}" VerticalAlignment="Top" />
                    <Grid>
                        <views:InformationTabItemsUserControl x:Name="InformationTabItemsControl" SelectedIndex="1" InformationTabItems="{Binding ElementName=InformationTabItems}"/>
                    </Grid>
                    <Grid VerticalAlignment="Center" HorizontalAlignment="Center">
                        <Launcher:LauncherInformationTabItemsUserControl x:Name="LauncherInformationTabItemsControl" LauncherInformationTabItems="{Binding ElementName=InformationTabItems}"/>
                    </Grid>
                </Grid>

                ....

                <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
                    <lex:GapTextControl FormatString="{Binding GameInformationTab.Header, ElementName=InformationTabItemsControl}"
                                        HorizontalAlignment="Left" VerticalAlignment="Center"
                                        Foreground="{StaticResource MainTextBrush}" FontWeight="SemiBold"
                                        Style="{StaticResource CustomGapTextControl}" FontSize="12"
                                        Visibility="{Binding GameInformationTab.IsSelected, Converter={StaticResource BoolToVisibilityCollapsedConverter}, ElementName=InformationTabItemsControl}"/>
                    <lex:GapTextControl FormatString="{lex:Loc Key=MainWindow.GameChangelog}"
                                        HorizontalAlignment="Left" VerticalAlignment="Center"
                                        Foreground="{StaticResource MainTextBrush}" FontWeight="SemiBold"
                                        Style="{StaticResource CustomGapTextControl}" FontSize="12"
                                        Visibility="{Binding GameChangelogTab.IsSelected, Converter={StaticResource BoolToVisibilityCollapsedConverter}, ElementName=InformationTabItemsControl}"/>
                    <Rectangle HorizontalAlignment="Right" VerticalAlignment="Center" Width="14" Height="14" Margin="5,0,0,-2">
                        <Rectangle.Fill>
                            <VisualBrush Stretch="Fill">
                                <VisualBrush.Visual>
                                    <iconPacks:PackIconMaterial Kind="ArrowExpandDown" Foreground="{StaticResource MainIconBrush}" />
                                </VisualBrush.Visual>
                            </VisualBrush>
                        </Rectangle.Fill>
                    </Rectangle>
                </StackPanel>
</Controls:MetroWindow>

MainWindow.cs

public partial class MainWindow : INotifyPropertyChanged
{
    public MainWindow()
    {
        this.DataContext = this;

        this.InitializeComponent();

        if (DesignerProperties.GetIsInDesignMode(this))
        {
            /* Does not work too */
            this.InformationTabItemsControl.InformationTabItemsControl.SelectedIndex = 1;
            this.InformationTabItemsControl.UpdateLayout();
            this.InformationTabItemsControl.InformationTabItemsControl.UpdateLayout();
        }
        else
        {
            //...
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string propertyName = null)
    {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

InformationTabItemsUserControl.xaml

    <UserControl
             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:Launcher"
             xmlns:Converter="clr-namespace:Launcher.Class.Converter" xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=PresentationFramework" xmlns:lex="http://wpflocalizeextension.codeplex.com" xmlns:Custom="http://metro.mahapps.com/winfx/xaml/controls" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" x:Class="Launcher.Views.InformationTabItemsUserControl"
             mc:Ignorable="d" 
             xmlns:views="clr-namespace:Launcher.Views"
             x:Name="_thisInformationTabItemsUserControl">
    <UserControl.Resources>

        <Converter:ValueGroupConverter x:Key="ValueGroupCollapsedConverter">
            <Converter:InverseBooleanConverter />
            <Converter:BooleanToVisibilityCollapsedConverter />
        </Converter:ValueGroupConverter>
    </UserControl.Resources>
    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
        <StackPanel.Style>
            <Style TargetType="{x:Type StackPanel}">
                <Style.Triggers>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=(ComponentModel:DesignerProperties.IsInDesignMode)}" Value="True"/>
                        </MultiDataTrigger.Conditions>
                        <Setter Property="Background" Value="{StaticResource PrimaryBackgroundBrush}"/>
                    </MultiDataTrigger>
                </Style.Triggers>
            </Style>
        </StackPanel.Style>
        <TabControl x:Name="InformationTabItemsControl" Background="{StaticResource TransparentBrush}" Margin="0,5,0,0" SelectedIndex="{Binding Path=SelectedIndex, ElementName=_thisInformationTabItemsUserControl}"
                TabStripPlacement="Top" Visibility="{Binding IsLauncherWindowActive, Converter={StaticResource ValueGroupCollapsedConverter}}">
            <TabControl.Style>
                <Style BasedOn="{StaticResource CustomInformationsTabControl}" TargetType="{x:Type TabControl}">
                    <Style.Triggers>
                        <MultiDataTrigger>
                            <MultiDataTrigger.Conditions>
                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=(ComponentModel:DesignerProperties.IsInDesignMode)}" Value="True"/>
                            </MultiDataTrigger.Conditions>
                            <Setter Property="SelectedIndex" Value="1"/>
                        </MultiDataTrigger>
                    </Style.Triggers>
                </Style>
            </TabControl.Style>
            <TabItem x:Name="GameInformationTabEntry" Header="{lex:Loc Key=MainWindow.GameInformation}" Custom:ControlsHelper.HeaderFontWeight="SemiBold" Padding="10,0,10,0" Style="{StaticResource NewsTabItem}">

            </TabItem>
            <TabItem x:Name="GameChangelogTabEntry" Header="{lex:Loc Key=MainWindow.GameChangelog}" Custom:ControlsHelper.HeaderFontWeight="SemiBold" Padding="10,0,10,0" Style="{StaticResource NewsTabItem}">

            </TabItem>
        </TabControl>
    </StackPanel>
</UserControl>

InformationTabItemsUserControl.cs

namespace Launcher.Views
{

    public partial class InformationTabItemsUserControl : UserControl, INotifyPropertyChanged
    {
        public InformationTabItemsUserControl()
        {
            InitializeComponent();

            this.GameInformationTab = GameInformationTabEntry;
            this.GameChangelogTab = GameChangelogTabEntry;
        }

        // Only used for a test
        public static readonly DependencyProperty selectedIndexProperty =
DependencyProperty.Register("SelectedIndex", typeof(int), typeof(InformationTabItemsUserControl), new FrameworkPropertyMetadata(default(int), new PropertyChangedCallback(SelectedIndexPropertyChanged)));

        public int SelectedIndex
        {
            get { return (int)GetValue(selectedIndexProperty); }
            set { SetValue(selectedIndexProperty, value); }
        }

        private static void SelectedIndexPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((InformationTabItemsUserControl)d).UpdateLayout();
        }

        public static readonly DependencyProperty informationTabItemsProperty =
DependencyProperty.Register("InformationTabItems", typeof(Grid), typeof(InformationTabItemsUserControl), new FrameworkPropertyMetadata(default(Grid), new PropertyChangedCallback(InformationTabItemsPropertyChanged)));

        public Grid InformationTabItems
        {
            get { return GetValue(informationTabItemsProperty) as Grid; }
            set { SetValue(informationTabItemsProperty, value); this.OnPropertyChanged(); }
        }

        // Does not update anything
        private static void InformationTabItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Grid grid = ((InformationTabItemsUserControl)d).InformationTabItems;
            grid.UpdateLayout();
        } 

        public static readonly DependencyProperty gameInformationTabProperty =
DependencyProperty.Register("GameInformationTab", typeof(TabItem), typeof(InformationTabItemsUserControl), new FrameworkPropertyMetadata(default(TabItem)));

        public TabItem GameInformationTab
        {
            get { return GetValue(gameInformationTabProperty) as TabItem; }
            set { SetValue(gameInformationTabProperty, value); this.OnPropertyChanged(); }
        }

        public static readonly DependencyProperty gameChangelogTabProperty =
DependencyProperty.Register("GameChangelogTab", typeof(TabItem), typeof(InformationTabItemsUserControl), new FrameworkPropertyMetadata(default(TabItem), new PropertyChangedCallback(GameChangelogTabPropertyChanged)));

        public TabItem GameChangelogTab
        {
            get { return GetValue(gameChangelogTabProperty) as TabItem; }
            set { SetValue(gameChangelogTabProperty, value); this.OnPropertyChanged(); }
        }

        // Does not work too
        private static void GameChangelogTabPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TabItem tabItem = ((InformationTabItemsUserControl)d).GameChangelogTab;
            tabItem.IsSelected = true;
            tabItem.UpdateLayout();
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propertyName = null)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

    }


}

0 个答案:

没有答案