I am trying to modify a TextBlock from a WPF code.
I have the following MainWindow XAML :
<Window x:Class="ChatServer.MainWindow"
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:local="clr-namespace:ChatServer"
mc:Ignorable="d"
ResizeMode="NoResize"
Title="Serveur de chat" Height="450" Width="800">
<Grid x:Name="Grille">
<DockPanel x:Name="DockP" LastChildFill="False">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" VerticalAlignment="Center" Margin="5,5,0,0" >
<Border BorderThickness="1" BorderBrush="Blue" DockPanel.Dock="Left" Height="20" Width="380">
<TextBlock HorizontalAlignment="Center" >Statut du Serveur</TextBlock>
</Border>
<Border BorderThickness="1" BorderBrush="Blue" DockPanel.Dock="Right" Height="20" Width="380">
<TextBlock HorizontalAlignment="Center">Gestion des Clients</TextBlock>
</Border>
</StackPanel>
<StackPanel x:Name="DataZ" Orientation="Horizontal" DockPanel.Dock="Top" VerticalAlignment="Center" Margin="5,0,0,0" >
<StackPanel x:Name="Server" Orientation="Vertical" DockPanel.Dock="Top" VerticalAlignment="Center" Margin="0,0,0,0">
<Border BorderThickness="1" BorderBrush="Blue" DockPanel.Dock="Left" Width="380">
<TextBox Name="ServerStatus" HorizontalAlignment="Center" VerticalAlignment="Top" Height="30" Width="380" Text="Serveur éteint" Background="#FFB0B0" TextAlignment="Center"/>
</Border>
<Border x:Name="ServerBorder" BorderThickness="1" BorderBrush="Blue" DockPanel.Dock="Left" Height="350" Width="380">
<StackPanel x:Name="SP" Orientation="Vertical" DockPanel.Dock="Top" Margin="0,0,0,0">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Margin="0,0,0,0">
<Button Content="Démarrer" Height="20" Width="60" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,10,10,10" Click="Demarre"/>
<Button Content="Arrêter" Height="20" Width="60" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,10,10,10" Click="Arrete"/>
</StackPanel>
<Border x:Name="LogBorder" BorderThickness="3" BorderBrush="Green" DockPanel.Dock="Left" Height="300" Margin="3,3,3,3">
</Border>
</StackPanel>
</Border>
I would like to add a Textblock inside the "LogBorder" Border (the last one). Here is the code (not working) :
public MainWindow()
{
InitializeComponent();
void CreateServerLogText()
{
TextBlock ServerLog = new TextBlock();
// <Border x:Name="LogBorder" BorderThickness="3" BorderBrush="Green" DockPanel.Dock="Left" Height="300" Margin="3,3,3,3">
// <TextBlock x:Name="ServerLog" Text="Logs du serveur" TextWrapping="Wrap"/>
// </ Border >
Grille.LogBorder.Child = ServerLog; // NOT WORKING
// Grille.DockP.DataZ.Server.ServerBorder.SP.LogBorder.Children.Add(ServerLog); // NOT WORKING
}
CreateServerLogText();
}
How do you "navigate" inside the XAML tree to add or modify content inside StackPanel and Border ?
The LogBorder field is a direct member of MainWindow. Even if the border is nested inside another control in xaml, the field itself is not nested. Simply remove Grille. to make it work. You must differentiate between the static C# code where the field is declared, and the nested data structure created dynamically at runtime by WPF based on the xaml code.
This test code works for me:
public MainWindow()
{
InitializeComponent();
TextBlock ServerLog = new TextBlock { Text = "Hello world" };
LogBorder.Child = ServerLog;
}
Side note: "not working" is not an adequate description of the problem. "Working" or "not working" requires the code to compile and to run. Only when it runs, you can test whether it is working as expected or not.
In your case, the code is not compiling. You get the compiler error
Error CS1061 'Grid' does not contain a definition for 'LogBorder' and no accessible extension method 'LogBorder' accepting a first argument of type 'Grid' could be found (are you missing a using directive or an assembly reference?)
The error tells you that the Grid (Grille) does not contain the expected LogBorder field. Which is correct since it is contained in MainWindow.
It is something like
TextBlock CreateServerLogText()
{
TextBlock ServerLog = new TextBlock();
LogBorder.Child = ServerLog;
return ServerLog;
}
TextBlock ServerLog = CreateServerLogText();
Related
I try to save and load TabItems via XamlWriter and XamlReader at runtime so that the user can restore the previous session. Each TabItem consists of UserControls and standard WPF controls like grids,buttons and checkboxes.
It all works fine until I try to subscribe to events of let's say a button.
If I raise them manually with RaiseEvent() they work, but if I click on them nothing happens. Even if I set IsEnabled=false the button is displayed as enabled. LogicalTreeHelper.FindLogicalNode gives me the right button, but the Click event also won't trigger. The IsLoaded property is false, so I assume there has to be some underlying problem with the initialization.
Basically this is the code to read from the file
StreamReader sw = new StreamReader(file);
XmlReader xmlReader = XmlReader.Create(sw);
TabItem tabItem = (TabItem)XamlReader.Load(xmlReader);
.. and this to save each TabItem to a seperate xml file
foreach (TabItem tabItem in tabControlMain.Items)
{
StreamWriter sw = new StreamWriter(Path.Combine(path,tabItem.Name + ".xml"), false);
string savedTab = XamlWriter.Save(tabItem);
sw.Write(savedTab);
sw.Close();
}
Here is an example TabItem saved to a file
<TabItem IsSelected="True" Header="Test" Name="tabItem1" HorizontalAlignment="Left" VerticalAlignment="Top" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:womoc="clr-namespace:WeldOsMqttOpcClient;assembly=blabla">
<TabItem.HeaderTemplate>
<DataTemplate DataType="{x:Type TabItem}">
<TextBox Margin="0,0,30,0" Text="{Binding Path=.}" />
</DataTemplate>
</TabItem.HeaderTemplate>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<womoc:UcOverviewTabPage Autoconnect="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid Name="gridParentOv">
<Grid Name="gridMqttOpcControls" Height="599.08" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<womoc:UcConnection Name="ucOpc" MinWidth="400" HorizontalAlignment="Right" VerticalAlignment="Stretch">
<GroupBox Header="OPC [10.5.51.130]" Name="groupBox" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ScrollViewer>
<Grid Name="gridTextBoxesWithValues" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Name="rowLabel" />
</Grid.RowDefinitions>
<Label Background="#FF008000" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelConnected" Width="190" Height="26" Margin="0,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.ColumnSpan="2">Connected!</Label>
</Grid>
</ScrollViewer>
</GroupBox>
</womoc:UcConnection>
</Grid>
<Grid Name="gridConnection" MinHeight="30" HorizontalAlignment="Stretch" VerticalAlignment="Bottom">
<Button Name="btnConnect" Width="55" Margin="100,0,0,10" HorizontalAlignment="Center" VerticalAlignment="Bottom" IsEnabled="False">Connect</Button>
<TextBox Name="tbIPAddress" Width="95" Height="18" Margin="0,0,100,10" HorizontalAlignment="Center" VerticalAlignment="Bottom" IsEnabled="False">10.5.51.130</TextBox>
<CheckBox Name="cbMqtt" Width="46" Height="15" Margin="20,0,0,10" HorizontalAlignment="Left" VerticalAlignment="Bottom" IsEnabled="False">Mqtt</CheckBox>
<CheckBox IsChecked="True" Name="cbOpc" Width="42" Margin="0,0,20,10" HorizontalAlignment="Right" VerticalAlignment="Bottom" IsEnabled="False">Opc</CheckBox>
</Grid>
</Grid>
</womoc:UcOverviewTabPage>
</Grid>
</TabItem>
UcOverviewTabPage is one of my UserControls, in which there is for example a button. I try to subscribe to the events manually ->
public UcOverviewTabPage()
{
InitializeComponent();
cbMqtt.Checked += CbMqtt_Checked;
cbMqtt.Unchecked += CbMqtt_Unchecked;
cbOpc.Checked += CbOpc_Checked;
cbOpc.Unchecked += CbOpc_Unchecked;
btnConnect.Click += BtnConnect_Click;
var children = LogicalTreeHelper.FindLogicalNode(this, "btnConnect") as Button;
bool loaded = children.IsLoaded;
// -> FALSE
}
Bear in mind, creating new custom UserControls during runtime works perfectly. The problem only occurs when reading out of the XML file.
I except the UserControls or any other Controls to work like they do when created during runtime. What am I missing?
I want to make change main panel content when I choice action in menu button.
Like main content page, setting page, content page on Main panel (in code used grid x:Name="main_~~~)
It for use just can make 3 and control visibility??
or Can use include like xml at Android and change include target??
( ex > includelayout="#layout/app_bar_main")
Mainwindow.xaml
<Window x:Class="M_C.MainWindow"
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:local="clr-namespace:M_C"
mc:Ignorable="d"
Title="MainWindow"
Width="1024" Height="768"
WindowStyle="None"
WindowState="Maximized"
WindowStartupLocation="CenterScreen">
<Grid x:Name="wide_Out" Background="#000000">
<Viewbox Stretch="Uniform">
<Grid Width="1024" Height="768" VerticalAlignment="Top">
<DockPanel x:Name="L_black" HorizontalAlignment="Left"
Height="768" LastChildFill="False" VerticalAlignment="Top" Width="62"
Background="#FF242424">
<Button Margin="15,8,0,0" Height="40"
VerticalAlignment="Top" Width="30"/>
</DockPanel>
<DockPanel x:Name="T_blue" HorizontalAlignment="Left"
Height="84" LastChildFill="False" Margin="62,0,0,0" VerticalAlignment="Top"
Width="968" Background="#FF248BC7">
<TextBlock Margin="200,5,200,0" Height="70"
TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="554"/>
</DockPanel>
<DockPanel x:Name="L_blue" HorizontalAlignment="Left"
Height="685" LastChildFill="False" Margin="62,83,0,0"
VerticalAlignment="Top" Width="82" Background="#FF248BC7"/>
<DockPanel x:Name="R_blue" HorizontalAlignment="Left"
Height="685" LastChildFill="False" Margin="940,83,0,0"
Background="#FF248BC7" Width="84"/>
<DockPanel x:Name="B_blue" HorizontalAlignment="Left"
Height="90" LastChildFill="False" Margin="143,678,0,0"
VerticalAlignment="Top" Width="799" Background="#FF248BC7">
<Image Margin="250,15,250,15" Height="70"
VerticalAlignment="Top" Width="290" />
</DockPanel>
<!--<DockPanel x:Name="main_content_panel"
HorizontalAlignment="Left" Height="594" LastChildFill="False"
Margin="144,84,0,0" VerticalAlignment="Top" Width="790">-->
<Grid x:Name="main_con_body" Margin="143,82,84,88"
Width="798" Height="594" Background="#ffffff">
</Grid>
<!--</DockPanel>-->
</Grid>
</Viewbox>
</Grid>
</Window>
You can Define Frame inside Your Window and navigate between as many page you want:
<Frame Name="FrameWithinGrid" >
</Frame>
and on button Click you can simply navigate:
private void button1_Click(object sender, RoutedEventArgs e)
{
FrameWithinGrid.Navigate(new System.Uri("Page1.xaml",
UriKind.RelativeOrAbsolute));
}
to know more See here
MVVM Approach
Make main_con_body be a ContentControl
Make Window's DataContext a viewmodel
Bind main_con_body's Content property to a viewmodel property of the data context
Define different DataTemplates for the various types of viewmodels that might be present
I can't set focus on first item of my ListBox. ListBox has some collection bound. It looks like, that first everything in code-behind doing its stuff then there is control initializing so I would have always -1 as SelectedIndex.
XAML
<Window x:Class="Labels.Szablony"
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:local="clr-namespace:Labels"
mc:Ignorable="d"
Title="Labels" Height="350" Width="250" WindowStartupLocation="CenterScreen"
ResizeMode="CanMinimize" KeyDown="Window_KeyDown" Background="#FFF6A300" >
<Window.DataContext>
<local:LabelGridViewModel/>
</Window.DataContext>
<ScrollViewer VerticalScrollBarVisibility="Hidden" VerticalContentAlignment="Center"
VerticalAlignment="Center" Background="#FFF6A300">
<Grid Background="#FFF6A300" Name="labelGrid">
<ListBox x:Name="SzablonyBox" ItemsSource="{Binding LabelsCollection, IsAsync=True}"
HorizontalAlignment="Center" VerticalAlignment="Top"
MinWidth="100" MinHeight="100" BorderBrush="{x:Null}"
Background="{x:Null}" TextSearch.Text="BLABLAB"
TextSearch.TextPath="Name" IsTextSearchEnabled="True"
VerticalContentAlignment="Center" Margin="0 25 0 0"
Width="250" HorizontalContentAlignment="Center">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter Event="PreviewKeyDown"
Handler="ListBoxItem_PreviewKeyDown"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel Width="214">
<TextBlock Text="{Binding Name}"
FontSize="12" Height="35"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Width="250"
TextAlignment="Center"/>
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox x:Name="InputText"
Text="{Binding Path=Filter, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Center" Height="22" TextWrapping="Wrap"
VerticalAlignment="Top" Width="250" Background="#FFF6A300"
IsEnabled="False" BorderBrush="#FFF6A300"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
Foreground="Black" SelectionBrush="{x:Null}"/>
</Grid>
</ScrollViewer>
What i'm trying to do looks like:
public Labels()
{
InitializeComponent();
LabelsBox.Focus();
LabelsBox.SelectedIndex = 0;
var item = LabelsBox.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem;
item.Focus();
}
Of course there is an exception, because item is null. Like I said SelectedIndex is always -1. What am I doing wrong ?
The ItemsSource Binding is asynchronous, so there are certainly not yet any items available while the constructor is running.
Change the Binding to be synchronous, i.e. the default behavior:
<ListBox ItemsSource="{Binding LabelsCollection}" ...>
You may also execute your initialization code as late as possible, by moving it to a Loaded event handler:
public Labels()
{
InitializeComponent();
...
Loaded += (s, e) =>
{
var item = (ListBoxItem)LabelsBox.ItemContainerGenerator.ContainerFromIndex(0);
item?.Focus();
};
}
In my application I have a control which renders a number of blocks on a timeline view (like a calendar). One can provide a template for the blocks by giving the timeline an appropriate DataTemplate.
I would like to separate the block DataTemplate from the main timeline view, putting the block into its own XAML. As such, I've created a XAML for the Block (called Block.xaml) and wrapped the DataTemplate inside a ResourceDictionary, inside this XAML.
I've added a code behind to the XAML (called Block.xaml.cs) in which I need to access some of the elements in the block. The issue is that ResourceDictionaries seem to hide the elements from the codebehind such that I can't access them. I can't use a UserControl instead - this seems to not work.
How can I access the elements of the Block DataTemplate from the code behind?
Many thanks in advance for your help.
Block.xaml:
<ResourceDictionary x:Class="Project.Windows.MainInterface.TimelinePanel.Block" 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:local="clr-namespace:Project.Windows.MainInterface.TimelinePanel" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:converters="clr-namespace:Project.Converters" >
<DataTemplate x:Key="ItemBlockTemplate">
<Grid Name="BlockParent" Width="Auto" Height="Auto" MinHeight="50" ClipToBounds="True" SizeChanged="BlockParent_OnSizeChanged">
<Border Panel.ZIndex="3" BorderBrush="{DynamicResource BackgroundGreyLight}" BorderThickness="1" CornerRadius="1" />
<Grid Margin="1" Background="{DynamicResource BlockBackgroundGradient}" d:LayoutOverrides="Width">
<TextBlock x:Name="blockName" Height="20" Margin="4,0,4,0" Padding="3" VerticalAlignment="Top" Panel.ZIndex="3" FontSize="10" Foreground="{DynamicResource TextLight}" Text="{Binding blockName}" TextTrimming="CharacterEllipsis" Visibility="Visible" />
<TextBlock x:Name="Duration" Margin="0,2,4,2" Padding="0,0,3,0" HorizontalAlignment="Right" VerticalAlignment="Bottom" Panel.ZIndex="5" FontSize="10" Foreground="{DynamicResource TextLight}" Text="{Binding FormattedDuration}" ToolTip="{Binding Duration}" />
<Grid Background="#FF0FA8FF" Opacity="0.7" />
</Grid>
</Grid>
</DataTemplate>
Snippet of the Timeline in the main interface:
...
<timeLineTool:TimeLineControl x:Name="Timeline" Height="50" MinWidth="50" Margin="0,0,12,0" HorizontalAlignment="Left" VerticalAlignment="Top" Items="{Binding Timeline}" SnapsToDevicePixels="True" UnitSize="{Binding UnitSize}" UseLayoutRounding="True">
<timeLineTool:TimeLineControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:BlockItemViewModel}">
<ContentControl>
<ContentPresenter Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="{Binding}" ContentTemplate="{StaticResource ItemBlockTemplate}" />
</ContentControl>
</DataTemplate>
</timeLineTool:TimeLineControl.ItemTemplate>
</timeLineTool:TimeLineControl>
...
...If I could use a UserControl instead of a ResourceDictionary for my Block, this would solve the problem, as all elements are automatically publicly available in the code behind for usercontrols.
Sample XAML:
<Window.Resources>
<ControlTemplate x:Key="ResourceName" TargetType="{x:Type Label}">
<Label Foreground="White" Content="{iconPacks:PackIconFontAwesome plug,Height=40,Width=40}"/>
</ControlTemplate>
</Window.Resources>
Code behind
ControlTemplate Dictionary:
private Dictionary<string, ControlTemplate> collection
{
get
{
Dictionary<string, ControlTemplate> controlTemplates = new Dictionary<string, ControlTemplate>();
controlTemplates.Add("ResourceName", FindResource("ResourceName") as ControlTemplate);
return controlTemplates;
}
}
Use ControlTemplate:
Label LBDisConnect = new Label();
LBDisConnect.Template = collection["ResourceName"];
LoginInfo.Children.Add(LBDisConnect);
I'm writing some Coded UI tests for a simple application and cannot seem to get the code to find Rectangle objects. In the specific case I have the color of the rectangle presents whether two strings match or not based on the fill color.
When trying to find the rectangle using the Coded UI Test Builder the parent object is being found instead of the rectangle. I am also seeing that the code returns that it is unable to find the rectangle when I have it search manually.
Below is the XAML for the page I am trying to test against:
<Page
x:Class="TestApp.ButtonTester"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="LayoutRoot">
<Grid.ChildrenTransitions>
<TransitionCollection>
<EntranceThemeTransition/>
</TransitionCollection>
</Grid.ChildrenTransitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Title Panel -->
<StackPanel Grid.Row="0" Margin="19,0,0,0">
<TextBlock Text="{StaticResource AppName}" Style="{ThemeResource TitleTextBlockStyle}" Margin="0,12,0,0"/>
<TextBlock Name="pageTitle" Text="Button Tester" Margin="0,-6.5,0,26.5" Style="{ThemeResource HeaderTextBlockStyle}" CharacterSpacing="{ThemeResource PivotHeaderItemCharacterSpacing}"/>
</StackPanel>
<!--TODO: Content should be placed within the following grid-->
<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,9.5,19,0">
<StackPanel Name="buttonValidator">
<TextBlock Name="verifyText" Text="Hi" HorizontalAlignment="Center" Style="{StaticResource LargeText}"/>
<Button Name="changeText" Content="Change Text" HorizontalAlignment="Center" Click="changeText_Click"/>
<TextBox Name="guessText" Text="Enter Text From Above" TextAlignment="Center" GotFocus="guessText_GotFocus" KeyDown="guessText_KeyDown"/>
<Button Name="verifyMatch" Content="Verify" HorizontalAlignment="Center" Click="verifyMatch_Click"/>
<Rectangle Name="matchAlert" Height="50" Width="50" Fill="Black" HorizontalAlignment="Center"/>
</StackPanel>
</Grid>
</Grid>
And here is the test code I currently have:
[TestMethod]
public void TestVerifyIncorrect()
{
UITestControl verifyMatch = new UITestControl(myApp);
verifyMatch.TechnologyName = "UIA";
verifyMatch.SearchProperties.Add("ControlType", "Button");
verifyMatch.SearchProperties.Add("AutomationId", "verifyMatch");
Gesture.Tap(verifyMatch);
UITestControl matchAlert = new UITestControl(myApp);
matchAlert.TechnologyName = "UIA";
matchAlert.SearchProperties.Add("ControlType", "Rectangle");
matchAlert.SearchProperties.Add("AutomationId", "matchAlert");
var fillColor = matchAlert.GetProperty("Fill");
}
I am also seeing the Test Builder unable to detect a rectangle even when it is being used as a control.
I also looked into the Rectangle class vs the Button class and it appears the first common link in their inheritance chains is with Windows.UI.Xaml.FrameworkElement. I'm unaware of what type of ojects the Coded UI is able to detect to know if that may be the cause of the issue.