Reputation: 51
I have a textbox in my xaml for an ID field that is pulled from a datasource. I want this value to be readonly so that users can't change this value. I have a button for the user to add a new object which of course will require an ID. I have a bool property on my object "IsNew" that gets set to true when the user clicks the "Add New" button. When that button is clicked, I want this textbox to be editable. So basically, when "IsNew = true". How can I accomplish this?
//My Xaml for the textbox:
<TextBox x:Name="ID"
Text="{Binding SelectedRecord.ID}"/>
//Xaml for the button
<Button x:Name="AddNewRecordButton"
Grid.Column="1"
Margin="20,0,5,0"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
HorizontalContentAlignment="Left"
Height="24"
Width="90"
Command="{Binding AddNewRecordCommand}"
CommandParameter="{Binding ElementName=window}"/>
//Code for the command method
public void AddNewRecord(object parameter)
{
var newRecord = new StockingReason();
Records.Add(newRecord);
SelectedRecord = newRecord;
newRecord.IsNew = true;
var control = parameter as IFocusable;
control?.SetFocus();
}
Upvotes: 1
Views: 2340
Reputation: 1687
Use an IValueConverter
:
public class InvertBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool val = (bool)value;
return !val;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
bool val = (bool)value;
return !val;
}
}
Example how use it
<Window x:Class="WpfApp1.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:metro="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:local="clr-namespace:WpfApp1"
xmlns:converter="clr-namespace:WpfApp1.MYCONVERTERNAMESPACE"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<converter:InvertBoolConverter x:Key="InvertBoolConverter" />
</Window.Resources>
<TextBox x:Name="ID"
Text="{Binding SelectedRecord.ID}"
IsReadOnly="{Binding IsNew, Converter={StaticResource InvertBoolConverter}}"/>
</Window>
Upvotes: 3
Reputation: 15
So I think if I understand your requirement, you can do the following:
1) Make sure the class that your code lives in implements INotifyPropertyChanged
2) Create a new Boolean property on your class called IsRecordReadOnly and have it forwarding the inverse of the selected records IsNew Flag.
3) Call propertychanged on your new boolean property after you've updated your selected selected record.
4) Bind the IsReadOnly property on the textbox to the IsRecordReadOnly property in the ViewModel.
public class ViewModel : INotifyPropertyChanged
{
private IRecord _selectedRecord;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public List<IRecord> Records = new List<IRecord>();
public IRecord SelectedRecord
{
get { return _selectedRecord; }
set
{
_selectedRecord = value;
OnPropertyChanged();
}
}
public bool IsRecordIdReadOnly
{
get { return !_selectedRecord?.IsNew ?? true; }
}
public void AddNewRecord(object parameter)
{
var newRecord = new StockingReason();
Records.Add(newRecord);
SelectedRecord = newRecord;
newRecord.IsNew = true;
var control = parameter as IFocusable;
control?.SetFocus();
}
}
and then your xaml...
<Grid>
<TextBox x:Name="ID"
Text="{Binding SelectedRecord.ID}" IsReadOnly="{Binding IsRecordReadOnly}"/>
</Grid>
Upvotes: 0
Reputation: 17637
You can use a IValueConverter, as pointed by Peter,
or you can also use a WPF Trigger
See WPF Trigger binding to MVVM property
<TextBox>
<TextBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsNew}" Value="True">
<Setter Property="TextBox.IsReadOnly" Value="False" />
</DataTrigger>
<DataTrigger Binding="{Binding IsNew}" Value="False">
<Setter Property="TextBox.IsReadOnly" Value="True" />
</DataTrigger>
<Trigger Property="Control.IsMouseOver" Value="true">
<Setter Property="Control.FontStyle" Value="Italic"></Setter>
<Setter Property="Control.Foreground" Value="Red"></Setter>
<Setter Property="Control.Background" Value="Yellow"></Setter>
</Trigger>
<Trigger Property="Button.IsPressed" Value="true">
<Setter Property="Control.Foreground" Value="Green"></Setter>
<Setter Property="Control.Background" Value="Blue"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Upvotes: 1