WPF binding ADUser doesn't update TextBox - wpf

I have a WPF GUI to show AD-objects loaded and operated through PowerShell.
The GUI works as planned, but some bindings does not update their controls (mainly TextBoxes). Some controls does however work without any problem.
I get the data through the Get-AD* cmdlets and it gets stored directly in the DataContext of a Grid higher up in the hierarchy. The properties I want to list are added to the cmdlet call with -Properties "EmailAddress", .... I have also tried -Properties *, but the bindings still doesn't update.
I suspect that only the properties that are inherited from the baseobject, works with the bindings. But I can be totaly of on this.
I have tried:
different settings for the binding, i.e. NotifyOnSourceUpdate...
separating the properties through Select-Object EmailAddress, ..., but this breaks it all and no controls are shown
using a test object (PSCustomObject) with the necessary properties, this also break the controls
if I assign the values directly in code, the textboxes show the correct info, i.e. $syncHash.tbUserotherTelephone.Text = $syncHash.gridObjInfo.DataContext.otherTelephone
For the example below, the object that is put in $syncHash.gridBaseInfoUser.DataContext is of type ADUser (BaseType: Microsoft.ActiveDirectory.Management.ADAccount)
Exampel of how the object the bindings are sourced from, is retrieved
$syncHash.gridObjInfo.DataContext = Get-ADUser $this.SelectedItem -Properties "EmailAddress", ...
$this.SelectedItems is the selected item in a DataGrid. I have verified that the correct data is retrieved at both Get-ADUser
Xaml hierarchy, showing two controls, one that gets the TextBox.Text entered, one that doesn't. Some code is omitted to save space.
<Window>
<Grid x:Name="gridMain">
...
<Grid x:Name="gridMainInfo" Grid.Row="1" DockPanel.Dock="Top" Width="Auto">
<Grid x:Name="gridObjInfo">
<Grid.Resources>
<Style x:Key="PropValueStyle" TargetType="{x:Type TextBox}">
<Setter Property="Grid.Column" Value="1"/>
<Setter Property="IsEnabled" Value="True"/>
<Setter Property="IsReadOnly" Value="True"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="">
<Setter Property="Background" Value="LightGray"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="{x:Null}">
<Setter Property="Background" Value="LightGray" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<!-- Other grids for other objectclasses -->
<Grid x:Name="gridBaseInfoUser" Grid.Row="{DynamicResource TypeObjInfoRowLoc}">
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ObjectClass}" Value="user">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<!-- This binding apparently does not work, so the textbox is empty -->
<Border Style="{StaticResource PropBorder}" Grid.Row="5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource PropTitleWidth}"/>
<ColumnDefinition Width="{StaticResource PropValueWidth}"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="tblUserotherTelephone" Style="{StaticResource PropTitleStyle}"/>
<TextBox x:Name="tbUserotherTelephone" Style="{StaticResource PropValueStyle}" Text="{Binding otherTelephone}"/>
</Grid>
</Border>
<!-- This binding apparently does work, so the textbox gets its Text set to the UserPrincipalName -->
<Border Style="{StaticResource PropBorder}" Grid.Row="6">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource PropTitleWidth}"/>
<ColumnDefinition Width="{StaticResource PropValueWidth}"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="tblUserUserPrincipalName" Style="{StaticResource PropTitleStyle}"/>
<TextBox x:Name="tbUserUserPrincipalName" Style="{StaticResource PropValueStyle}" Text="{Binding UserPrincipalName}"/>
</Grid>
</Border>
</Grid>
...
</Window>

Related

Creating Combo Box UserControl with Multi Column

I have multi-column combo box but i want to use these combo box in many places.So I think i need to create combo box user control.But problem is itemsource of each combo box is not same.
Currently my multi column combo box,
<ComboBox Grid.Row="0"
Grid.Column="1"
Margin="2"
Width="150"
x:Name="cboemployee"
IsEditable="True"
DisplayMemberPath="EmployeeID"
SelectedValuePath="EmployeeID"
ItemsSource="{Binding EmployeeList}">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}" BasedOn="{StaticResource MetroComboBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Width="400" x:Name="gd">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="300"/>
</Grid.ColumnDefinitions>
<TextBlock Margin="2" Grid.Column="0" Text="{Binding EmployeeID}"/>
<TextBlock Margin="2" Grid.Column="1" Text="{Binding EmployeeName}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ComboBoxItem.IsSelected" Value="True">
<Setter TargetName="gd" Property="Background" Value="{StaticResource AccentBaseColorBrush}"></Setter>
<Setter TargetName="gd" Property="TextElement.Foreground" Value="White"></Setter>
</Trigger>
<Trigger Property="ComboBoxItem.IsMouseOver" Value="True">
<Setter TargetName="gd" Property="Background" Value="{StaticResource AccentColorBrush}"></Setter>
<Setter TargetName="gd" Property="TextElement.Foreground" Value="White"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
I am not sure i need custom combo box or combo box user control and Please let me known which is best for my requirement with binding different item source?

xaml User control layout -Sizing

I have a parent user control which has a detail section and a tree section in it. My intention is on two toggle button i should be able to hide and show the controls.
<DockPanel>
<DockPanel DockPanel.Dock="Left">
<view:ListBoxUserControl DockPanel.Dock="Top" Visibility="{Binding IsListVisible ,Converter={StaticResource BoolToVisibilityConverter}}"/>
<view:TreeUserControl DockPanel.Dock="Top" Visibility="{Binding IsTreeVisible,Converter={StaticResource BoolToVisibilityConverter}}"/>
</StackPanel>
<view:DetailSectionUserControl/>
</StackPanel>
IsListVisible and IsTreeVisible is set based on two toggle button in the view.
so when IsListVisible is false the ListBoxUserControl will be hidden and TreeUserControl will move to top. this is working well.
But there are two problems here i face.
1) Requirement is that the both controls should be having same size. here the first tree will be created based on the items in it and rest of the space will be taken by TreeUserControl. How shall i make the size even.
2) When i add an item to ListBoxUserControl the control just grows and TreeUserControl size get reduced. How shall i get a scroll instead .
Try:
<Grid>
<Grid.RowDefinitions>
<RowDefinition>
<RowDefinition.Style>
<Style TargetType="{x:Type RowDefinition}">
<Setter Property="Height" Value="*" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsListVisible}" Value="False">
<Setter Property="Height" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</RowDefinition.Style>
</RowDefinition>
<RowDefinition>
<RowDefinition.Style>
<Style TargetType="{x:Type RowDefinition}">
<Setter Property="Height" Value="*" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsTreeVisible}" Value="False">
<Setter Property="Height" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</RowDefinition.Style>
</RowDefinition>
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<view:ListBoxUserControl Visibility="{Binding IsListVisible ,Converter={StaticResource BoolToVisibilityConverter}}"/>
</ScrollViewer>
<view:TreeUserControl Grid.Row="1" Visibility="{Binding IsTreeVisible,Converter={StaticResource BoolToVisibilityConverter}}"/>
</Grid>

DataTrigger for Visibility of a control inside a DataTemplate not working

I have a ListBox which is binded to a List and it has a DataTemplate for it's items. Everything in DataTemplate works good except for visibility of second TextBlock! I don't understand what I'm doing wrong and I don't want to use converter, I've checked these links already:
Bind Bool to Visibility of TextBlock within a ListBox
Binding a Button's visibility to a bool value in ViewModel
<ListBox Name="lsb_Jobs" Grid.Column="3" Grid.Row="2" Grid.RowSpan="6" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
BorderThickness="0,1,0,0" Padding="0,5" Margin="0,10,5,5">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="45">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.Style>
<Style TargetType="Grid">
<Style.Triggers>
<DataTrigger Binding="{Binding Importance}" Value="0">
<Setter Property="Background" Value="LimeGreen"/>
</DataTrigger>
<DataTrigger Binding="{Binding Importance}" Value=".25">
<Setter Property="Background" Value="NavajoWhite"/>
</DataTrigger>
<DataTrigger Binding="{Binding Importance}" Value=".5">
<Setter Property="Background" Value="Gold"/>
</DataTrigger>
<DataTrigger Binding="{Binding Importance}" Value=".75">
<Setter Property="Background" Value="Orange"/>
</DataTrigger>
<DataTrigger Binding="{Binding Importance}" Value="1">
<Setter Property="Background" Value="OrangeRed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<CheckBox Name="chb_IsDone" IsChecked="{Binding Done}" FlowDirection="LeftToRight" Checked="job_Done_Checked" Unchecked="job_Done_Checked"/>
<TextBlock Text="{Binding Subject}" Grid.Column="1" Foreground="Black" VerticalAlignment="Center" FontSize="14"/>
<TextBlock Text="Done" Grid.Column="3" HorizontalAlignment="Right" VerticalAlignment="Center" Visibility="Hidden" Margin="0,0,170,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Done}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Can you tell me why it's not working?! I did exactly the same thing that I did for other controls! They work but TextBlock does not get visible! Is there any problem with Visibility property of TextBlock!? I tried FrameworkElement.Visibility already but that does not work either
The Visibility="Hidden" that you explicitly set on the TextBlock is overriding whatever the Style does. Style is applied first, then finally explicit assignments in the tag attributes are applied. This makes sense: If you have a global TextBlock style and you set properties on an individual TextBlock, you want the global values for those properties to be overridden.

Usercontrol style trigger not working

I am pretty sure this question has been asked from time to time since I found another question with about the same contents, here. But when I try to figure using all those pages, I'm just stuck...
This is what I'm trying to do. I created a usercontrol to select a file and show the path to the file in a textbox. Just like in HTML (input type=file). That all works great and as expected. But when I try to change the colour of the textbox using a trigger (FilePathIsValid), it just does not work. The dependency properties all work fine, as said above. But the style just is not assigned to the textbox.
Here is my XAML - can anybody tell me what I'm doing wrong? (Code Behind here, if needed)
<UserControl x:Class="Project.Controls.SelectFileBox"
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:Controls="clr-namespace:Project.Controls"
x:Name="ThisUserControl"
mc:Ignorable="d" d:DesignHeight="30" d:DesignWidth="300">
<UserControl.Resources>
<!-- This does not work... -->
<Style TargetType="{x:Type Controls:SelectFileBox}">
<Style.Triggers>
<Trigger Property="FilePathIsValid" Value="false">
<Setter Property="TextBoxBorderColor" Value="red"/>
</Trigger>
</Style.Triggers>
</Style>
<!-- Neither does this: FilePathIsValid can't be found -->
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="FilePathIsValid" Value="false">
<Setter Property="BorderBrush" Value="red"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Margin="3" IsEnabled="{Binding ElementName=ThisUserControl,Path=TextBoxIsEnabled}" Text="{Binding ElementName=ThisUserControl,Path=FilePath}" BorderThickness="{Binding ElementName=ThisUserControl, Path=TextBoxBorderThickness}"/>
<Button Grid.Column="1" Margin="0,3,3,3" Content="{Binding ElementName=ThisUserControl, Path=ButtonText}" Click="SelectFileClick"/>
</Grid>
Ok, I understood the problem after looking at the codebehind.
All you need to do is add a binding to the BorderBrush property on the TextBox like below to get the right BorderBrush applied.
BorderBrush="{Binding ElementName=ThisUserControl, Path=TextBoxBorderColor}"
Full XAML for TextBox element:
<TextBox Grid.Column="0" Margin="3"
IsEnabled="{Binding ElementName=ThisUserControl,Path=TextBoxIsEnabled}"
Text="{Binding ElementName=ThisUserControl,Path=FilePath}"
BorderThickness="{Binding ElementName=ThisUserControl, Path=TextBoxBorderThickness}"
BorderBrush="{Binding ElementName=ThisUserControl, Path=TextBoxBorderColor}"/>
I have tried and tested, below is the screenshot
Alternative Way:
You could have a style for TextBox and have data triggers to change the borderbrush:
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ThisUserControl,
Path=FilePathIsValid}" Value="False">
<Setter Property="BorderBrush" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
With this approach, you don't need style for SelectFileBox and binding for BorderBrush property on TextBox.
If i understand correctly you want to set the textBoxbroder as red if the path is invalid then change your code as below
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="FilePathIsValid" Value="false">
<Setter Property="BorderBrush" Value="red"/>
</Trigger>
</Style.Triggers>
</Style>

DataTrigger on RadioButton IsChecked

I have a scenario where I need to hide some content based on whether a radio button is checked or unchecked. For some reason I can't get this to work the way I expect it to. The behavior is the opposite of what I expect. If I adjust my xaml to accomodate the actual behavior that I'm seeing it everything gets hidden.
Essentially what I have is two radio buttons labeled Fixed and Cycle. When Fixed is checked I want the textbox associated with Fixed to have a visible foreground and the textbox associated with Cycle to have a transparent foreground and vice-versa. What I'm seeing is the exact opposite.
Here's my trigger:
<Grid.Resources>
<Style TargetType="TextBox" x:Key="FixedModeStyle">
<Setter Property="Foreground" Value="Transparent" />
<Setter Property="Width" Value="40" />
<Setter Property="Height" Value="20" />
<Setter Property="Margin" Value="10" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked,
ElementName=rbtFixedMode}" Value="True" >
<Setter Property="Foreground"
Value="{DynamicResource My.Fonts.Global.LightForeground}" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="TextBox" x:Key="CycleModeStyle">
<Setter Property="Foreground" Value="Transparent" />
<Setter Property="Width" Value="40" />
<Setter Property="Height" Value="20" />
<Setter Property="Margin" Value="10" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked,
ElementName=rbtCycleMode}" Value="True" >
<Setter Property="Foreground"
Value="{DynamicResource My.Fonts.Global.LightForeground}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
Here's my radio buttons and associated textboxes:
<RadioButton x:Name="rbtFixedMode" Content="Fixed"
GroupName="AveragingMode"
Foreground="{DynamicResource My.Fonts.Global.LightForeground}"
IsChecked="{Binding AveragingWindowMode,
Converter={StaticResource EnumToBooleanConverter},
ConverterParameter={x:Static Processors:AveragingMode.Fixed}}" />
<DockPanel Grid.Row="1" IsEnabled="{Binding IsChecked, ElementName=rbtFixedMode}">
<TextBox x:Name="txtFixedIntervalLength"
Style="{StaticResource FixedModeStyle}" DockPanel.Dock="Left"
Text="{Binding AveragingWindowFixedLength}" />
</DockPanel>
<RadioButton x:Name="rbtCycleMode" Content="Cycle"
GroupName="AveragingMode" Grid.Row="2"
Foreground="{DynamicResource My.Fonts.Global.LightForeground}"
IsChecked="{Binding AveragingWindowMode,
Converter={StaticResource EnumToBooleanConverter},
ConverterParameter={x:Static Processors:AveragingMode.Cycles}}" />
<DockPanel Grid.Row="3" IsEnabled="{Binding IsChecked, ElementName=rbtCycleMode}">
<TextBox x:Name="txtCycleIntervalLength"
Style="{StaticResource CycleModeStyle}" DockPanel.Dock="Left"
Text="{Binding AveragingWindowCycleLength}"/>
<TextBlock x:Name="txbCycles" Text="Cycles" Margin="4,10"
Foreground="{DynamicResource My.Fonts.Global.LightForeground}" />
</DockPanel>
Any ideas?
Just making the text transparent is a bad idea, the user will still be able to edit it while it is transparent. Besides that the code is obfuscated and redundant. Do not create two styles for a TextBox, both containing the same setters; create a base-style and use BasedOn for sub-styles.
Not quite sure where your code goes wrong, i would suggest you clean it up, maybe there is some logical error, also here is a working example:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Page.Resources>
</Page.Resources>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<RadioButton Name="rbCycle" GroupName="g1" Content="Cycle"/>
<RadioButton Name="rbFixed" GroupName="g1" Content="Fixed" Grid.Column="1"/>
<TextBox Grid.Row="1" Text="cycle box">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=rbCycle}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<TextBox Grid.Row="1" Grid.Column="1" Text="fixed box">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=rbFixed}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
</ScrollViewer>
</Page>
If you're using binding to set the values of your radio buttons, don't use groups. If you're using groups, don't use binding. The two don't play well together.
That may not be the cause of what you're seeing. But I bet it is. And it's certainly interfering with your ability to diagnose the problem, because after you start clicking on buttons their binding doesn't work anymore.

Resources