Reputation: 43
currently I have a boolean dependency property which is bound the following way:
public bool Status
{
get { return (bool)GetValue(StatusProperty); }
set { SetValue(StatusProperty, value); }
}
public static readonly DependencyProperty StatusProperty =
DependencyProperty.Register("Status", typeof(bool),
typeof(UIButton), new PropertyMetadata(false));
which I am using within a Trigger like this..
....
<Condition Binding="{Binding Path=Status}" Value="True" />
....
Everything works fine, but now I want to extend this boolean dependency property to something similar like that:
public class State : DependencyObject
{
public bool? status
{
get { return (bool?)GetValue(statusProperty); }
set { SetValue(statusProperty, value); }
}
public static readonly DependencyProperty statusProperty =
DependencyProperty.Register("status", typeof(bool?),
typeof(UIButton), new PropertyMetadata(false));
public State()
{
}
public State(bool status)
{
this.status = status;
}
public override string ToString()
{
if (status)
return "activated"; // this strings change on runtime, depending on user language.. simplified for demonstration purpose
else
return "deactivated"; // this strings change on runtime, depending on user language.. simplified for demonstration purpose
}
}
My goal is, to override the ToString method of the boolean object or in other words, add a custom text if I bind this dependency property to a textbox like this
<TextBlock Text="{Binding Path=Status.status}"/>
but still can use it in my Trigger like shown above.
With the current code I'm getting XAML parse exceptions... not sure if this construct is valid.. I think not. :P
Any ideas on how I could implement such functionality?
Thanks.
EDIT
Currently I'm using this solution:
public class State
{
public bool? status { get; set; }
public string statusString {
get {
if (status == true)
return "activated";
else if (status == false)
return "deactivated";
else
return "";
}
set {}
}
public State()
{
}
public State(bool? status)
{
this.status = status;
}
}
with the following bindings:
<TextBlock Text="{Binding Path=Status.statusString}"/>
and
<Condition Binding="{Binding Path=Status.status}" Value="False" />
this works pretty well, the only disadvantage is, that I need to completly exchange the whole object, when changing the state.
myState = new State(false);
and not like...
myState.status = false;
Upvotes: 0
Views: 985
Reputation: 863
Have you considered using a custom converter for this? It will convert a dependency property's value however you define. An example in your case could be:
public class StatusToTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
bool? b = (bool?)value;
if (b == true) return "activated";
else if (b == false) return "deactivated";
else return "not set";
}
catch (Exception)
{
return "invalid";
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
bool? returnValue = null;
string s = (string)value;
if (s == "activated") returnValue = true;
else if (s == "deactivated") returnValue = false;
return returnValue;
}
catch (Exception)
{
return null;
}
}
}
Then, in your XAML define StatusToTextConverter as a resource and use the converter in your binding expression on the TextBlock:
<UserControl.Resources>
<local:StatusToTextConverter x:Key="statusToTextConverter"/>
</UserControl.Resources>
<TextBlock Text="{Binding Path=Status, Converter="{StaticResource statusToTextConverter"}"/>
This way your trigger condition will still be bound to the bool property but the TextBlock will display the bool value as something meaningful.
EDIT: I wrote that solution thinking you wanted to bind it to a TextBox, not a TextBlock. If you are just displaying the value, you don't need to define anything in the ConvertBack method and can simply throw a NotImplementedException.
Upvotes: 1
Reputation: 1256
Here is your solution;
public class State : UIElement
{
public State()
{
}
private bool _status;
public bool Status
{
get { return (bool)GetValue(StatusProperty); }
set
{
SetValue(StatusProperty, value);
if (value != _status)
{
_status = value;
if (value)
{
this.StatusText = "Activated";
}
else
{
this.StatusText = "Deactivated";
}
RaiseStatusChangedEvent();
}
}
}
// Using a DependencyProperty as the backing store for Status. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StatusProperty =
DependencyProperty.Register("Status", typeof(bool), typeof(State), new PropertyMetadata(InternStatusChanged));
static void InternStatusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Nullable<bool> value = e.NewValue as Nullable<bool>;
if (value.HasValue)
{
((State)d).Status = value.Value;
}
}
public string StatusText
{
get { return (string)GetValue(StatusTextProperty); }
set { SetValue(StatusTextProperty, value); }
}
// Using a DependencyProperty as the backing store for StatusText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StatusTextProperty =
DependencyProperty.Register("StatusText", typeof(string), typeof(State), new PropertyMetadata(""));
// Create a custom routed event by first registering a RoutedEventID
// This event uses the bubbling routing strategy
public static readonly RoutedEvent StatusChangedEvent = EventManager.RegisterRoutedEvent(
"StatusChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(State));
// Provide CLR accessors for the event
public event RoutedEventHandler StatusChanged
{
add { AddHandler(StatusChangedEvent, value); }
remove { RemoveHandler(StatusChangedEvent, value); }
}
// This method raises the SelectedPathChanged event
void RaiseStatusChangedEvent()
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(State.StatusChangedEvent);
RaiseEvent(newEventArgs);
}
}
Test:
public partial class MainWindow : Window
{
State state;
public MainWindow()
{
InitializeComponent();
state = new State();
state.StatusChanged += new RoutedEventHandler(state_StatusChanged);
state.Status = true;
}
void state_StatusChanged(object sender, RoutedEventArgs e)
{
MessageBox.Show(this.state.StatusText);
}
}
Upvotes: 0