Overriding binded TextBox value - c#

There is a TextBox on window whose value is binded to view model property (simple, usual binding).
<TextBox x:Name="textBoxName" Text="{Binding Name}"/>
Now I need to show on the TextBox either the value coming from binding or empty string depending on RadioButton value on the same window (and view model).
One idea to achieve the goal is to programmatically clear the binding, set empty value, and later set the binding again. But I guess this is not a good solution.
I'm new to WPF and MVVM and would like to hear how this should be done properly (in "MVVM way")?

You could use a multi value converter:
public class BooleanMultiValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool isChecked = (bool)values[0];
string name = (string)values[1];
return isChecked ? "" : name;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
then you bind your TextBox like this:
<StackPanel>
<TextBox>
<TextBox.Text>
<MultiBinding Converter="{StaticResource MultiValueConverter}" >
<Binding Path="IsChecked" ElementName="rb"/>
<Binding Path="Name"/>
</MultiBinding>
</TextBox.Text>
</TextBox>
<StackPanel Orientation="Horizontal">
<RadioButton Name="rb"/>
<RadioButton/>
</StackPanel>
</StackPanel>
add this as direct child to your window:
<Window.Resources>
<converters:BooleanMultiValueConverter x:Key="MultiValueConverter"/>
</Window.Resources>
and don't forget to add the namespace:
xmlns:converters="clr-namespace:WPFTest.Converters"
This should work:

There are a few things you can do here.
Change value of Name Property based on what was selected on Radio Button
Use a converter that checks radio button value and updates text box text
Use Trigger to change the text box text when radio button selection is changed.
All three are fairly easy to implement, let me know if you need code for any.

Related

How to implement a converter from string to Visibility

So I have a ProgressRing and a TextBlock and I am trying to implement this basic hack, which is to display both elements when TextBlock's Text gets assigned a value (anything other than null), else both elements should hide when TextBlock's Text is null.
My Xaml looks like below. TextBlock's Text is binded to MessageForProgressRing and its Visibility is binded to both MessageForProgressRing and TargetNullValue. Same for me ProgressRing:
<StackPanel Panel.ZIndex="100" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center">
<mahControls:ProgressRing Height="50" IsActive="True" Width="50" Visibility="{Binding MessageForProgressRing, TargetNullValue=Collapsed, FallbackValue=Visible}" Foreground="White" Margin="0,0,0.2,0" />
<TextBlock Text="{Binding MessageForProgressRing}" Visibility="{Binding MessageForProgressRing, TargetNullValue=Collapsed, FallbackValue=Visible}"/>
</StackPanel>
Then, in code behind I just trigger the property and assign it a value on some button event handlers:
private void closeApplicationButtonTask()
{
((CaptureViewModel)DataContext).MessageForProgressRing = "Closing... ";
Application.Current.MainWindow.Close();
}
However, in my ViewModelBase (the parent of all my view models) it pops an error on OnPropertyChanged saying:
Requested value 'Closing...' was not found.
I think I need a converter because Visibility is binded to Closing... right? If yes how can I achieve it?
P.S I couldn't do it in OnPropertyChanged because I don't see the value to assign it. Also I don't think it is a good idea since it gets called big time before, during and after the execution.
I usually prefer to solve this problem by having a boolean property in my view model (e.g. HasMessageForProgressRing or IsProgressRingVisible). It's usually a more general-purpose solution. Then you can use a BooleanToVisibilityConverter.
If you truly want to implement a converter, just create a class that implements IValueConverter. The Convert implementation of this should be a piece of cake for your simple use case. ConvertBack isn't necessary in most cases (and won't be in yours). It would look something like this:
public class NullToCollapsed : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value != null ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Multilingual WPF Application: not working with combobox

I have created a multilingual WPF application using Andre's answer from here. I'm binding text like this
<TextBlock Text="{DynamicResource Create}"/>
and can switch from english to french at runtime - nice! However, this does not work with ItemsSource. For example, I have a ComboBox that should display all available languages:
<ComboBox ItemsSource="{Binding AllLanguages, Source={StaticResource Locator}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{DynamicResource LanguageId}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Set up like this, the combobox displays no text. If I set the textblock's text inside to Text={LanguageId}, I see the LanguageIds 'eng', 'fr' etc., so the binding works.
When using a converter:
<TextBlock Text="{Binding LanguageId, Converter={StaticResource DynamicResourceConverter}"/>
languages are displayed as "English" and "French". When I switch the language, however, the converter is not called again and the language names are not updated - so that is no real workaround.
I'd be very thankful for a tip on the cause and how to fix this.
I'll explain first why a few things are not working.
....
<DataTemplate>
<TextBlock Text="{DynamicResource LanguageId}"/>
</DataTemplate>
....
This is a short hand for Text="{DynamicResource ResourceKey='LanguageId'}" which is a static string literal and does not involve any binding.
It would be great if the following was available, but unfortunetly is NOT POSSIBLE because the target for the binding is not a DependancyProperty.
....
<DataTemplate>
<TextBlock Text="{DynamicResource ResourceKey={Binding LanguageId}}"/>
</DataTemplate>
....
You are close with your workaround. My suggestion would be to try the following:-
....
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource DynamicResourceConverter}">
<Binding Path="LanguageId"/>
<Binding Path="SomeOtherPropertyThatChangesWhenLanguageIsSwitched" Source="{StaticResource Locator}"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
....
You will need to expand the DynamicResourceConverter to now implement also IMultiValueConverter. In a MultiBinding scenario, if either bound expression changes then the converter is called again. You would write the Converter such that it only operates on values[0] of the supplied object array as the second value is not needed and only provided a trigger for the converter to be called again.
public class DynamicResourceConverter: IValueConverter, IMultiValueConverter
{
....
// original converter implementation for IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
....
}
// newly added converter implementation for IMultiValueConverter
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//call the original converter method with one value (assuming you've checked the array has at least one item!!
return Convert(values[0], targetType, parameter, culture)
}
....
}

Collapsing/expanding action with wpf buttons

First off, let me state I am an amateur when it comes to wpf. I am trying to create an a collapsing/expanding type action for a wpf button, meaning when a user clicks a button, I would like the button selected to expand a new list of buttons beneath it. This is meant to be the navigation type for the web-enabled application. I would also like to create a collapsing interaction when the button is pressed again on an opened list.
There is a default control for this in WPF, named the Expander. If you want to change the appearance or the animations you could look into templating and styling of WPF. By default this control should meet most of your requirements.
My first idea is to use a ToggleButton and bind its IsChecked property to a the visibility of the element you want to show. You would need a converter then to convert the boolean Checked value to a Visibility value. Here is an example:
<Grid>
<Grid.Resources>
<BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
</Grid.Ressources>
<ToggleButton x:Name="toggleButton" Content="Toggle" />
<Grid Visibility={Binding IsChecked, ElementName=toggleButton, Converter={StaticResource BoolToVisibilityConverter}}>
<!-- place your content here -->
</Grid>
</Grid>
The converter is a class implementig IValueConverter:
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool i = value is bool ? (bool) value : false;
return i ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Just use a ToggleButton and bind the visibility of the section to its IsChecked state as normally done in the Expander control (which you of course could just use instead).

WPF XamComboEditor/ComboEditorTool - Setting default text

I'm trying to add some default text to combo boxes that will show when there is no item selected. I'm using a style to acheive this which works great when the combo is first loaded.
<Style TargetType="{x:Type igRibbon:ComboEditorTool}" x:Key="PleaseSelect">
<Style.Triggers>
<Trigger Property="SelectedIndex" Value="-1">
<Setter Property="Text" Value="Please Select" />
</Trigger>
</Style.Triggers>
</Style>
<igRibbon:ComboEditorTool Style="{StaticResource PleaseSelect}"
ItemsSource="{Binding MyItems}" SelectedItem="{Binding MySelectedItem }" />
But when the combo's selected item is reset (by setting it to null, which sets the SelectedIndex to -1) it fails to display the default text (even though the the trigger does fire), what could be the reason for this? Is there a better way to reset the selected item?
Cheers
Here is the solution that I used, thanks to #AlexPaven for the idea:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
{
return "Please Select";
}
else
{
return value;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string && ((string)value) == "Please Select")
{
return null;
}
else
{
return value;
}
}
I'm not familiar with the Infragistics suite, but I suspect it's the same thing as with regular combo boxes: since you have a binding on SelectedItem, the Text cannot be set to an item that blatantly disobeys that binding; the Text IS a representation of the SelectedItem. If the SelectedItem is null, then the Text must also be a representation of null.
I'm guessing (didn't try it and I may be just plain wrong) you could probably accomplish this with an IValueConverter that returns a custom string when the passed object is null (and returns the object unchanged otherwise), set on the SelectedItem binding.
It's been a while since this question was asked, but let me answer it with a more Infragistics related answer.
Let's start with a short side node:
We have to be careful when using XamComboEditor without specifying the namespace,
because in the Infragistics Framework the class is defined two times.
1. Infragistics.Windows.Editors.XamComboEditor
2. Infragistics.Controls.Editors.XamComboEditor
Referring to the Infragistics Help, the recommended one is the Infragistics.Windows.Editors.XamComboEditor
See the About xamComboEditor:
We recommend that you use the xamComboEditor control instead of the xamComboEditor (Input) control. The xamComboEditor (Input) is being planned for retirement over the next few years and will not receive any new features.
And now to your question:
Both, the Infragistics.Windows.Editors.XamComboEditor and the derived Infragistics.Windows.Ribbon.ComboEditorTool, have a property for setting a default text for null values. This property is called:
NullText
The text to display when the value of the editor is null and the editor is not in edit mode. The default value is empty string. (Inherited from Infragistics.Windows.Editors.TextEditorBase)
Also the Infragistics.Controls.Editors.XamComboEditor provides such a property. It is called:
EmptyText
Gets/Sets the Text that should be displayed when the editor doesn't have anything selected. (Inherited from Infragistics.Controls.Editors.ComboEditorBase)
Example for ComboEditorTool:
Referencing the following dlls:
InfragisticsWPF4.Editors.v18.1
InfragisticsWPF4.Ribbon.v18.1
InfragisticsWPF4.v18.1
xaml-Snippet:
xmlns:ribbon="http://infragistics.com/Ribbon"
...
<ribbon:ComboEditorTool Id="SampleComboEditorTool"
NullText="Select ..."
ItemsSource="{Binding }"
/>
Screenshot:
Example for Infragistics.Windows.Editors.XamComboEditor:
Referencing the following dlls:
InfragisticsWPF4.Editors.v18.1
InfragisticsWPF4.v18.1
xaml-Snippet:
xmlns:editors="http://infragistics.com/Editors"
...
<editors:XamComboEditor Width="120" Height="23"
ItemsSource="{Binding}"
NullText="Select ..."
/>
Screenshot:
Example for Infragistics.Controls.Editors.XamComboEditor:
Referencing the following dlls:
InfragisticsWPF4.Controls.Editors.XamComboEditor.v18.1
InfragisticsWPF4.v18.1
xaml-Snippet:
xmlns:ig="http://schemas.infragistics.com/xaml"
...
<ig:XamComboEditor Width="120" Height="23"
ItemsSource="{Binding}"
EmptyText="Select ..."
/>
Screenshot:
Second side note: the first occurrence I've found for the property NullText was in the Help Doc of Version 2012.1. See here

Bind StackPanel.Visibility to the Visibility property of its children

I'm relatively new to DataBinding and just reading into it.
What I want to do is the following:
I have a StackPanel with a number of child controls:
<StackPanel Orientation="Horizontal">
<TextBox x:Name="textbox1" Width="100">1</TextBox>
<TextBox x:Name="textbox2" Width="100">2</TextBox>
<TextBox x:Name="textbox3" Width="100">3</TextBox>
</StackPanel>
The visibility property of the textboxes can be changed by code.
Now, if all TextBoxes are set to Visibility=Collapsed, i also want StackPanel.Visibility set to Collapsed, but if one or more TextBoxes are shown (Visibility=Visible), StackPanel.Visibility should also be set to Visible.
Can this be achieved with a simple DataBinding or do I have to implement this functionality in C# code?
I can not think of a way to do this directly through databinding.
Personally I would have a view model behind the view, and set the views DataContext to the view model.
In the view model I would then have a property telling the view if all the textboxes are collapsed. That property would be set by code. Then bind the stackpanel visibility to that property.
(The property must either be a dependancy property, or the view model must implement INotifyPropertyChanged for the view to automatically update)
Have you considered setting the visibility of the TextBoxes to Hidden? This will "hide" the space that is assigned for the TextBoxes. Assuming their are no other controls in the StackPanel, then it will not be visible.
Of course, this solution may make some naive assumptions about your implementation.
If you need the more complex scenario, I would attempt the following:
Note: This is psuedocode - may not compile..
1) Use a MultiBinding
<StackPanel>
<StackPanel.Visibility Converter={StaticResource visibilityConverter}>
<MultiBinding.Bindings>
<Binding ElementName="textBox1" Path="Visibility" />
<Binding ElementName="textBox2" Path="Visibility" />
<Binding ElementName="textBox3" Path="Visibility" />
</MultiBinding.Bindings>
</StackPanel.Visibility>
</StackPanel>
2) Declare the Converter
<Window.Resources>
<local:VisibilityConverter x:Key="visibilityConverter" />
</Window.Resources>
3) Define the Converter
public class VisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
Visibility text1Vis = (Visibility)values[0];
Visibility text2Vis = (Visibility)values[1];
Visibility text3Vis = (Visibility)values[2];
if (text1Vis == text2Vis == text3Vis == Visibility.Collapsed)
return Visibility.Collapsed;
return Visibility.Visible;
}
}

Categories

Resources