我目前正在尝试将.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));
}
}
}