I'm quite confused as at runtime I get this error:
The application called an interface that was marshalled for a different thread. (0x8001010E (RPC_E_WRONG_THREAD))'
I have a on object that has:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
FontFamily="Segoe MDL2 Assets"
Foreground="{Binding ImageColor, Mode=OneWay}"
Text="{Binding ImageSrc, Mode=OneWay}" />
<TextBlock
Grid.Column="1"
VerticalAlignment="Center"
Text="{Binding VisitDescr, Mode=OneWay}" />
</Grid>
in the class I have
public string ImageSrc
{
get
{
switch (Type)
{
case "c1":
return "\xE8B9";
break;
default:
return "\xE8A5";
break;
}
}
}
public Brush ImageColor
{
get
{
switch (Type)
{
case "c1":
return new SolidColorBrush(Colors.MediumOrchid);
break;
case "c2":
return new SolidColorBrush(Colors.DarkOrchid);
default:
return new SolidColorBrush(Colors.Red);
break;
}
}
}
The image is returned without any error but the Color generate the error and is NOT changed.
How is it possible I get a marshalled error?
I've found the issue... it was using the work library.
I've updated it to:
using System.Windows.Media;
and now is working.
But why it got Marshalling and not type conversion error?
Related
I have a listview like:
<ListView Name="ListViewItems" Grid.Row="2" Foreground="White" ItemsSource="{Binding Items}"
SelectedItem="{Binding CurrentSelectedItem ,Mode=TwoWay}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" SelectionMode="Single"
HorizontalContentAlignment="Stretch"
ScrollViewer.VerticalScrollBarVisibility="Auto"
VerticalAlignment="Stretch" BorderThickness="0" >
<ListView.ItemTemplate>
<DataTemplate >
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Width="0" Visibility="Collapsed" Content="{Binding Id}"/>
<Label Grid.Column="0" Content="{Binding Name}" HorizontalContentAlignment="Left" Foreground="White" FontWeight="Bold" Background="Transparent"/>
<Label Grid.Column="1" Content="{Binding Provider}" HorizontalContentAlignment="Left" Foreground="White" Background="Transparent"/>
<Label Grid.Column="0" Grid.ColumnSpan="2" Background="Transparent"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
As it seems when i change the selected item (by clicking on another listview item) the set of CurrentSelectedItem will be called.
private MyObject _currentSelectedItem;
public MyObject CurrentSelectedItem
{
get => _currentSelectedItem;
set
{
if (Condition)
{
// here i want to have previous item seleced
// Currently i do nothing here
}
else
{
_currentSelectedItem = value;
}
}
}
When Condition is true if I do nothing the CurrentSelectedItem will have previous value which is what I want, BUT in the UI the selected item (highlighted item) is the one I selected recently.
What I want is to prevent such behavior in UI. I mean CurrentSelectedItem has not changed bu UI it changed.
Any solution to prevent such behavior? thanks in advance.
Solution:
As #Zeb-ur-Rehman we should save the previous state in _previousSelectedItem. but in the else statement i don't assign value to _currentSelectedItem as a result when I do _currentSelectedItem = _previousSelectedItem both current and previous mentioning the same object. and therefor OnPropertyChanged will not update the binded view.
By the way, the only way I could somehow manage this scenario is to save _currentSelectedMap in the previous and update UI by _currentSelectedMap = null.then after a small delay (it should be a delay) update UI by saved value like this:
if (Condition)
{
_previousSelectedItem = _currentSelectedItem;
_currentSelectedItem = null;
NotifyOfPropertyChange(()=> CurrentSelectedItem);
Task.Delay(100).ContinueWith(x =>
{
Application.Current.Dispatcher.Invoke(() =>
{
_currentSelectedItem = _previousSelectedItem;
NotifyOfPropertyChange(()=> CurrentSelectedItem);
});
});
}
else
{
_currentSelectedItem = value;
}
Here is what you need to do in your property setter.
private MyObject _previousSelectedItem;
private MyObject _currentSelectedItem;
public MyObject CurrentSelectedItem
{
get => _currentSelectedItem;
set
{
if (Condition)
{
_previousSelectedItem = _currentSelectedItem;
_currentSelectedItem = value;
}
else
{
_currentSelectedItem = _previousSelectedItem;
}
NotifyOfPropertyChange(()=> CurrentSelectedItem);
}
}
You need to keep track of previous value which you can capture when changing the currentSelectedItem. Next time if the condition is not true then just assign your currentSelecteditem the previous value.
Hope it will work for you.
Edit:
I haven't mentioned that you need to NotifyOfPropertyChange(()=> CurrentSelectedItem); becuase i thought it's too obvious. Your code should work this way as well. Insead of changing value in Dispatcher, as the value is already 2 way bind to control. This is the power of WPF binding.
In a Tabbed interface application i'm trying to pass the TabItem Header string or the object contained in the selected TabItem to the view model to use it to
publish an event like this:
In the View (xaml):
<TabControl x:Name="MyTC"
prism:RegionManager.RegionName="{x:Static inf:RegionNames.MainRegion}"
SelectedItem="{Binding Path=TabControlSelectedItem,UpdateSourceTrigger=PropertyChanged,Mode=Twoway}"
Cursor="Hand"
Grid.Row="0"
Grid.Column="1">
<TabControl.ItemTemplate>
<DataTemplate>
<!--DataContext="{Binding ElementName=MyTC, Path=SelectedItem}"-->
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center"
Margin="3"
Text="{Binding Path=DataContext.DataContext.HeaderInfo, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabItem}}}"
/>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding HeaderClickCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
In View Model
//***********************************************************
//Constructor
public ShellWindowViewModel(IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
this.HeaderClickCommand = new DelegateCommand(OnHeaderClick);
}
//SelectedItem Binding
private object tabControlSelectedItem;
public object TabControlSelectedItem
{
get { return tabControlSelectedItem; }
set
{
if (tabControlSelectedItem != value)
{
tabControlSelectedItem = value;
OnPropertyChanged("TabControlSelectedItem");
}
}
}
//*****************************************************************************************************
//this handler publish the Payload "SelectedSubsystem" for whoever subscribe to this event
private void OnHeaderClick()
{
//EA for communication between Modules not within Modules
string TabHeader = (TabControlSelectedItem as TabItem).Header.ToString();
eventAggregator.GetEvent<SubsystemIDSelectedEvent>().Publish(TabHeader);
}
but there is something wrong because when i click the TabItem nothing happen and when i inserted a breakpoint # TabControlSelectedItem
property i found it contain the view namespace.i want the TabControlSelectedItem to get the selected Tab header string or the object in
the selected tab item.
Your help is very much appreciated.
I just tried something similar and it works fine.
Here is my xaml
<TabControl ItemsSource="{Binding Matches}"
SelectedItem="{Binding SelectedRecipe}">
<TabControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{Binding Path=Date}" />
<TextBlock Grid.Column="1"
TextAlignment="Center"
Text="{Binding Path=Name}" />
</Grid>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
And then in my viewmodel
public object SelectedRecipe
{
get
{
return _selectedRecipe;
}
set
{
_selectedRecipe = value;
OnNotifyPropertyChanged("SelectedRecipe");
}
}
I want to implement ListBox Grouping on WP7. I found this article is very useful. Actually I made the grouping works. But I got a problem with ListItem horizontal stretch. I guess I need to set ItemContainerStyle and change HorizontalContentAlignment as Stretch. But it doesn't work for this case (if set the ItemTemplate directly, it works). Any suggestions? Thanks a lot!
Here is the code, the ListItem is supposed to be stretched, but it's centered instead.
C#:
public class GroupingItemsControlConverter : IValueConverter
{
public object Convert(object value, Type tagetType, object parameter, CultureInfo culture)
{
var valueAsIEnumerable = value as IEnumerable;
if (null == valueAsIEnumerable)
{
throw new ArgumentException("GroupingItemsControlConverter works for only IEnumerable inputs.", "value");
}
var parameterAsGroupingItemsControlConverterParameter = parameter as GroupingItemsControlConverterParameters;
if (null == parameterAsGroupingItemsControlConverterParameter)
{
throw new ArgumentException("Missing required GroupingItemsControlConverterParameter.", "parameter");
}
var groupSelectorAsIGroupingItemsControlConverterSelector = parameterAsGroupingItemsControlConverterParameter.GroupSelector as IGroupingItemsControlConverterSelector;
if (null == groupSelectorAsIGroupingItemsControlConverterSelector)
{
throw new ArgumentException("GroupingItemsControlConverterParameter.GroupSelector must be non-null and implement IGroupingItemsControlConverterSelector.", "parameter");
}
// Return the grouped results
return ConvertAndGroupSequence(valueAsIEnumerable.Cast<object>(), parameterAsGroupingItemsControlConverterParameter);
}
private IEnumerable<object> ConvertAndGroupSequence(IEnumerable<object> sequence, GroupingItemsControlConverterParameters parameters)
{
// Validate parameters
var groupKeySelector = ((IGroupingItemsControlConverterSelector)(parameters.GroupSelector)).GetGroupKeySelector();
var orderKeySelector = ((IGroupingItemsControlConverterSelector)(parameters.GroupSelector)).GetOrderKeySelector();
if (null == groupKeySelector)
{
throw new NotSupportedException("IGroupingItemsControlConverterSelector.GetGroupSelector must return a non-null value.");
}
// Do the grouping and ordering
var groupedOrderedSequence = sequence.GroupBy(groupKeySelector).OrderBy(orderKeySelector);
// Return the wrapped results
foreach (var group in groupedOrderedSequence)
{
yield return new ContentControl { Content = group.Key, ContentTemplate = parameters.GroupStyle };
foreach (var item in group)
{
yield return new ContentControl { Content = item, ContentTemplate = parameters.ItemStyle };
}
}
}
public object ConvertBack(object value, Type tagetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException("GroupingItemsControlConverter does not support ConvertBack.");
}
}
public class GroupingItemsControlConverterParameters
{
public DataTemplate GroupStyle { get; set; }
public DataTemplate ItemStyle { get; set; }
public IGroupingItemsControlConverterSelector GroupSelector { get; set; }
};
public abstract class IGroupingItemsControlConverterSelector
{
public abstract Func<object, IComparable> GetGroupKeySelector();
public virtual Func<IGrouping<IComparable, object>, IComparable> GetOrderKeySelector() { return g => g.Key; }
}
public class GroupingItemsControlConverterSelector : IGroupingItemsControlConverterSelector
{
public override Func<object, IComparable> GetGroupKeySelector()
{
return (o) => (o as ItemViewModel).Group;
}
}
XAML:
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.Resources>
<DataTemplate x:Key="GroupHeaderTemplate">
<Border BorderBrush="Yellow" BorderThickness="1" Margin="12,3,12,12" Padding="6" VerticalAlignment="Center">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Number}" HorizontalAlignment="Left" Margin="6,0,0,0" FontSize="22" Foreground="White"/>
<TextBlock Grid.Column="1" Text="{Binding Name}" HorizontalAlignment="Right" Margin="0,0,6,0" FontSize="22" Foreground="White"/>
</Grid>
</Border>
</DataTemplate>
<DataTemplate x:Key="CustomItemTemplate">
<Grid Margin="12,3,12,12" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="{Binding Number}" HorizontalAlignment="Left" Margin="6,0,0,0" FontSize="22" Foreground="White"/>
<TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding Name}" HorizontalAlignment="Right" Margin="0,0,6,0" FontSize="22" Foreground="White"/>
</Grid>
</DataTemplate>
<local:GroupingItemsControlConverter x:Key="GroupingItemsConverter" />
<local:GroupingItemsControlConverterSelector x:Key="GroupingItemsSelector" />
<local:GroupingItemsControlConverterParameters x:Key="GroupingItemParameters"
GroupStyle="{StaticResource GroupHeaderTemplate}"
ItemStyle="{StaticResource CustomItemTemplate}"
GroupSelector="{StaticResource GroupingItemsSelector}"
/>
<Style TargetType="ListBoxItem" x:Key="CustomItemContainerStyle">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</Grid.Resources>
<ListBox x:Name="TheListBox"
ItemsSource="{Binding Items, Converter={StaticResource GroupingItemsConverter}, ConverterParameter={StaticResource GroupingItemParameters}}"
ItemContainerStyle="{StaticResource CustomItemContainerStyle}" />
</Grid>
ListBox grouping? You should consider using the LongListSelector from the Silverlight Toolkit. And to simplify the binding for that, you can use the LongListCollection collection type (Check the entire example, for details).
Then you can simply create apps that groups values, for example like this:
I'm building a wp7 app.
I have a UserControl that displays a news article headline, teaser, and image. The entire class is pretty short:
public partial class StoryControl : UserControl
{
public Story Story { get; private set; }
public StoryControl()
{
InitializeComponent();
}
internal StoryControl(Story story) : this()
{
this.Story = story;
Teaser.Text = story.Teaser;
Headline.Text = story.Title;
if (story.ImageSrc == null)
{
Thumbnail.Visibility = Visibility.Collapsed;
} else
{
Thumbnail.Source = new BitmapImage(story.ImageSrc);
}
}
}
And the corresponding XAML:
<Grid x:Name="LayoutRoot" Background="Transparent" Margin="0,0,0,20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image x:Name="Thumbnail" Grid.Column="0" Width="89" HorizontalAlignment="Left" VerticalAlignment="Top" />
<!-- sometimes there's a hanging word in the headline that looks a bit awkward -->
<TextBlock x:Name="Headline" Grid.Column="1" Grid.Row="0" Style="{StaticResource PhoneTextAccentStyle}" TextWrapping="Wrap" HorizontalAlignment="Left" FontSize="23.333" VerticalAlignment="Top" />
<TextBlock x:Name="Teaser" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" HorizontalAlignment="Left" Style="{StaticResource PhoneTextSubtleStyle}" TextWrapping="Wrap" VerticalAlignment="Top" Width="384"/>
</Grid>
Is there a way to do with with less code-behind and more XAML? Some way to use binding to bind the text for Headline and Teaser to properties of the Story, while not crashing if Story is null?
About about the image? I've got a bit of logic there; is there some way to automatically do that in XAML, or am I stuck with that in C#?
Looks like a ViewModel is in order:
public class StoryViewModel
{
readonly Story story;
public StoryViewModel(Story story)
{
this.story = story;
}
public string Teaser { get { return story == null ? "" : story.Teaser; } }
public string Title { get { return story == null ? "" : story.Title; } }
public bool IsThumbnailVisible { get { return story != null && story.ImageSrc != null; } }
public BitmapImage Thumbnail { get { return IsThumbnailVisible ? new BitmapImage(story.ImageSrc) : null; } }
}
Making your codebehind nice and simple:
public partial class StoryControl : UserControl
{
public Story Story { get; private set; }
public StoryControl()
{
InitializeComponent();
}
internal StoryControl(Story story)
: this()
{
this.DataContext = new StoryViewModel(story);
}
}
And your XAML becomes a set of bindings:
<Grid x:Name="LayoutRoot" Background="Transparent" Margin="0,0,0,20">
<Grid.Resources>
<BooleanToVisibilityConverter x:Key="booleanToVisiblityConverter"/>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Visibility="{Binding IsThumbnailVisible, Converter={StaticResource booleanToVisiblityConverter}}" Source="{Binding Thumbnail}" Grid.Column="0" Width="89" HorizontalAlignment="Left" VerticalAlignment="Top" />
<!-- sometimes there's a hanging word in the headline that looks a bit awkward -->
<TextBlock Text="{Binding Title}" Grid.Column="1" Grid.Row="0" Style="{StaticResource PhoneTextAccentStyle}" TextWrapping="Wrap" HorizontalAlignment="Left" FontSize="23.333" VerticalAlignment="Top" />
<TextBlock Text="{Binding Teaser}" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" HorizontalAlignment="Left" Style="{StaticResource PhoneTextSubtleStyle}" TextWrapping="Wrap" VerticalAlignment="Top" Width="384"/>
</Grid>
Ok, it would probably be possible to do this with just model (story) and view (xaml) via fallbackvalues and more complex converters, but i hope you'll find that viewmodels give you the most power in terms of testable, brick-wall-less, view-specific logic...
I have a text box in my application which is data bound to a decimal field in my class and the binding mode is two way. I am using StringFormat={0:c} for currency formatting.
This works fine as long as I don't touch 'UpdateSourceTrigger'. If I set UpdateSourceTrigger=PropertyChanged , It stops formatting the text that I am entering.
here is my code example
Employee.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace Converter
{
public class Employee : INotifyPropertyChanged
{
int _employeeNumber;
string _firstName;
string _lastName;
string _department;
string _title;
decimal _salary;
public Employee()
{
_employeeNumber = 0;
_firstName =
_lastName =
_department =
_title = null;
}
public int EmployeeNumber
{
get { return _employeeNumber; }
set
{
_employeeNumber = value;
OnPropertyChanged("EmployeeNumber");
}
}
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
OnPropertyChanged("FirstName");
}
}
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
OnPropertyChanged("LastName");
}
}
public string Department
{
get { return _department; }
set
{
_department = value;
OnPropertyChanged("Department");
}
}
public string Title
{
get { return _title + " salary: " + _salary.ToString(); }
set
{
_title = value;
OnPropertyChanged("Title");
}
}
public decimal Salary
{
get { return _salary; }
set
{
_salary = value;
OnPropertyChanged("Salary");
OnPropertyChanged("Title");
}
}
public override string ToString()
{
return String.Format("{0} {1} ({2})", FirstName, LastName, EmployeeNumber);
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName);
this.PropertyChanged(this, args);
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}
EmployeeList.cs:
using System.Collections.ObjectModel;
namespace Converter
{
public class EmployeeList : ObservableCollection<Employee>
{
}
}
Window1.xaml:
<Window x:Class="Converter.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Converter"
Title="Window1" Height="500" Width="500">
<Window.Resources>
<local:EmployeeList x:Key="myEmployeeList">
<local:Employee EmployeeNumber="1" FirstName="John" LastName="Dow" Title="Accountant" Department="Payroll" Salary="25000.00" />
<local:Employee EmployeeNumber="2" FirstName="Jane" LastName="Austin" Title="Account Executive" Department="Customer Management" Salary="25000.00" />
<local:Employee EmployeeNumber="3" FirstName="Ralph" LastName="Emmerson" Title="QA Manager" Department="Product Development" Salary="25000.00" />
<local:Employee EmployeeNumber="4" FirstName="Patrick" LastName="Fitzgerald" Title="QA Manager" Department="Product Development" Salary="25000.00" />
<local:Employee EmployeeNumber="5" FirstName="Charles" LastName="Dickens" Title="QA Manager" Department="Product Development" Salary="25000.00" />
</local:EmployeeList>
<local:StringToDecimalCurrencyConverter x:Key="StringToDecimalCurrencyConverter"></local:StringToDecimalCurrencyConverter>
</Window.Resources>
<Grid DataContext="{StaticResource myEmployeeList}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="240" />
<RowDefinition Height="45" />
</Grid.RowDefinitions>
<ListBox Name="employeeListBox" ItemsSource="{Binding Path=., Mode=TwoWay}" Grid.Row="0" />
<Grid Grid.Row="1" DataContext="{Binding ElementName=employeeListBox, Path=SelectedItem, Mode=TwoWay}">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0">First Name</Label>
<Label Grid.Row="1" Grid.Column="0">Last Name</Label>
<Label Grid.Row="2" Grid.Column="0">Title</Label>
<Label Grid.Row="3" Grid.Column="0">Department</Label>
<Label Grid.Row="4" Grid.Column="0">Salary</Label>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Mode=TwoWay, Path=FirstName}" />
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Mode=TwoWay, Path=LastName}" />
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Mode=TwoWay, Path=Title}" />
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Mode=TwoWay, Path=Department}" />
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding Mode=TwoWay, StringFormat=\{0:c\}, UpdateSourceTrigger=PropertyChanged, Path=Salary}" />
<TextBlock Grid.Row="5" Grid.Column="1" Text="{Binding Mode=OneWay, Converter={StaticResource StringToDecimalCurrencyConverter}, Path=Salary}" />
</Grid>
</Grid>
</Window>
If you remove 'UpdateSourceTrigger=PropertyChanged' from the above code it works fine.
I have also tried using Converter instead of the StringFormat, and still the problem is not solved.
The problem is that if you use a converter and update on property changed then WPF will ignore property changes while it is the process of updating the source property. Since the PropertyChanged event is raised from the setter, WPF ignores it.
The reason it does this is that if you typed "1" in the text box, this would get converted to the decimal value 1.0 and then get converted back to the string "$1.00". This would change the text in the text box and reset the cursor, so if you tried to type "12" you'd end up with "2$1.00".
Note that your Employee object is getting updated, and the problem is just that the TextBox isn't getting a newly formatted value.
If you really do want that behavior, you can set IsAsync=True on the binding and WPF will no longer see it as a reentrant change and will allow it. This has also changed in .NET 4.0, so if you upgrade to the latest version of the framework then you should see the behavior you expect.