Radio buttons binding on specific value without prefix on WPF - wpf

I have a window that has two radio buttons, the 2nd has an IntegerUpDown.
The "IsChecked" property is binding to the IntegerUpDown.
I want the IntegerUpDown to have values between 1 and 100, but in case "1" is selected - I want the other radio button to be turned on.
The issue starts when typing, for example, "12". The "1" immediately flicks the radio button without waiting for the other numbers.
My WPF code:
Radio Button 1:
<RadioButton
Content="{Resx PatternDialog.MatchOnlySuffix, DefaultValue='suffix'}"
IsChecked="{Binding dnsLabelCount, Converter={local:DnsLabelCountToBoolConverter}}"/>
Radio Button 2:
<RadioButton
Name="matchUpToNumberSuffixRb"
Content="{Resx PatternDialog.MatchUpToNumberSuffix, DefaultValue='Match'}"
IsChecked="{Binding dnsLabelCount, Converter={local:DnsLabelCountToBoolConverter Invert=True}}"/>
The IntegerUpDown:
<IntegerUpDown
Name="updown"
Value="{Binding dnsLabelCount}"
Width="55"
ForceRange="True"
MinValue="1"
MaxValue="100"
IsEnabled="{Binding IsChecked, ElementName=matchUpToNumberSuffixRb}"/>
This is my converter, which I know should not be so, but I'm not sure what to change it to.
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var result = (int)value == 1;
return Invert ? !result : result;
}

add a small Delay to Binding (Value="{Binding dnsLabelCount, Delay=250}"), and the source property will not be updated immediately

Related

Span in Contentpresenter not working properly

I have stumbled upon a small problem and I'm not sure how to avoid it or work around it and whether it's a bug or a "feature".
When rendering a span with text in it, it seems to be disconnected from the logical tree when using a content presenter to render it. It does not bubble IsMouseOver (or probably any event) and Hyperlinks inside the span also won't fire any associated code.
<ContentPresenter>
<ContentPresenter.Content>
<!--Normally this would be a binding, but it behaves the same.-->
<Span>
Test <Hyperlink Click="Hyperlink_OnClick">Testlink</Hyperlink>
</Span>
</ContentPresenter.Content>
</ContentPresenter>
Inspecting the visual tree with Snoop indeed shows that the TextBlock used to display the span does not receive IsMouseOver-Events from it's inline elements while they themselves do indeed register them correctly (when you expand the inline property and navigate to them; they just refuse to pass them on). Also when attaching a message box to the click handler, nothing happens when you click on the link.
<TextBlock Grid.Row="1">
<Span>
Test <Hyperlink Click="Hyperlink_OnClick">Testlink</Hyperlink>
</Span>
</TextBlock>
This one on the other hand works as expected. The IsMouseOver works fine and even the Link works.
The premise of my problem is, that I want to dynamically bind the text of the TextBlock to something. But I can't bind the text-property to a span directly so I'm using a content presenter which does the job (but is broken). Is this a bug or some feature/implication that I'm unaware of? And is there another way to bind a span to something to display it with working event handling & hyperlink clicks?
You could use a converter that returns a TextBlock with the Span added to its Inlines collection:
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Span span = value as Span;
TextBlock textBlock = new TextBlock();
textBlock.Inlines.Add(span);
return textBlock;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
XAML:
<ContentPresenter Content="{Binding Span, Converter={StaticResource MyConverter}}" />

WPF Radio Button Fires Converter in strange order

I am writing a simple program using the MVVM Model on WPF. Basicly when the user clicks a radio button in a group of radio buttons, it will update a property in the View Model with the new Account number. The problem is, when I click a different button the converter is called for the new button IsChecked Binding, and then after that it runs the converter for the previous button IsChecked binding(for losing its checked status).
This is causing a problem, since the new button is updating the value of the property with the correct account number, and then when the old button calls the converter, it gets converted back to the old value. I have hacked it to work by adding a static variable to the class, and if the IsChecked property is false, just return the value in the static variable. Does anyone have a better solution for Short Circuting the Converter Call on the box that loses its checked status. Code is below:
Converter:
class RadioToAccountConverter : IValueConverter
{
static string myValue; //HACK TO MAKE IT WORK
object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return parameter.ToString();
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ((bool)value)
{
myValue = parameter.ToString(); // Hack to make it work
return parameter.ToString();
}
return myValue; // Hack to make it work
}
}
XAML:
<RadioButton Foreground="HotPink"
Grid.Column="0"
Content="6087721"
Tag="6087721"
IsChecked="{Binding Account, Converter={StaticResource Radio2Value}, Mode=OneWayToSource, ConverterParameter=6087721}">
</RadioButton>
<RadioButton Foreground="HotPink"
Grid.Column="1"
Content="BFSC120"
IsChecked="{Binding Account, Converter={StaticResource Radio2Value}, Mode=OneWayToSource, ConverterParameter='BFSC120'}">
</RadioButton>
<RadioButton Foreground="HotPink"
Grid.Column="2"
Content="BFSC121"
IsChecked="{Binding Account, Converter={StaticResource Radio2Value}, Mode=OneWayToSource, ConverterParameter=BFSC121}">
</RadioButton>
<RadioButton Foreground="HotPink"
Grid.Column="3"
Content="BFSC206"
IsChecked="{Binding Account, Converter={StaticResource Radio2Value}, Mode=OneWayToSource, ConverterParameter=BFSC206}">
</RadioButton>
Property:
public const string AccountPropertyName = "Account";
private string _account;
/// <summary>
/// Sets and gets the Account property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public string Account
{
get
{
return _account;
}
set
{
if (_account == value)
{
return;
}
RaisePropertyChanging(AccountPropertyName);
_account = value;
RaisePropertyChanged(AccountPropertyName);
}
}
Any Help Is Greatly Appreciated.
Based on what I understand, you want to give users the ability to select from a list of account numbers. You're choice of presentation (view) is a group of radio buttons.
If that is true, the key part is this: you want to give users the ability to select from a list of account numbers. This means that the control you should use is a ListBox, since users should select one of the appropriate values. Now, since you are looking to use radio buttons visually, you simply have to supply an alternative ItemsSource.ItemContainerStyle.
XAML:
<ListBox ItemsSource="{Binding AccountNumbers, Mode=OneWay">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<RadioButton Content="{Binding}" IsChecked="{Binding IsSelected, RelativeSource={x:Static RelativeSource.TemplatedParent}}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Note that you'll need to add another property on your ViewModel (I named it AccountNumbers). For example:
public IReadOnlyCollection<string> AccountNumbers { ... }
Of course, the underlying collection can be a observable if you need it to be, but that's really up to you.
If you define a GroupName on each RadioButton, WPF will manage the IsChecked states for you.
You could bind the state with a {Binding SomeProperty, Mode=OneWayToSource} if you want the ViewModel to be aware of state.
One way to approach this would be to bind each RadioButton's IsChecked property to the whole ViewModel, just bind it to something like
IsChecked="{Binding WholeViewModel, Mode=OneWayToSource, Converter={StaticResource MyRadioButtonConverter}, ConverterParameter=SomethingReallyUnique}"
...where the public property WholeViewModel is a property that does a return this; in the getter. This would let you have access to the ViewModel and enough information to query the ViewModel to see if the radiobutton should be checked or not. But, only do this if the GroupName DependencyProperty doesn't somehow give you what you want.
To process the clicking on the buttons, then, to actually change the ViewModel state, you'd implement an ICommand in your ViewModel and bind the Command property of the RadioButton to {Binding ClickedCommand} and define a CommandParameter with any string you want. This approach will guarantee a one-way relationship to the IsChecked state, preventing the thing you're describing, I think.
I'll work up a code sample if you think you'd like one.

Overlay 2 controls and toggle which one is visible using WPF

This is a general question which will apply to any WPF control.
What I am trying to do is place two controls on top of each other and toggle which is visible.
I.e I want to control the visbility of them such that only one control is visible at one time.
One control will normally be hidden but upon some event will be displayed on top of the other control.
I have tried changing the z order and tried using the visibility property, but while I can make the normally hidden control appear, the normally displayed control is also visible.
E.g. the button below is normally hidden, but upon an a menu item click, for example, the ShowAboutBox property in a viewmodel will be set, changing the visibility property. At which point the button should be visible and not the dockpanel.
<Grid>
<Button Visibility="{Binding ShowAboutBox, Converter={StaticResource BoolToVisConverter}}">
<Button.Content>About My App</Button.Content></Button>
<DockPanel Canvas.ZIndex="0" LastChildFill="True"></DockPanel>
</Grid>
I'm not that experienced in WPF but assuming that this should be quite easy - any suggestions?
EDIT:
The code above shows a mix of techniques I tried. And probably confuses the issue. Most recently I have tried the following to no avail either.
<Grid>
<Button Visibility="{Binding ShowAboutBox, Converter={StaticResource BoolToVisConverter}}">
<Button.Content>About My App</Button.Content></Button>
<DockPanel></DockPanel>
</Grid>
Changing the visibility of the button causes it to display, but the dock panel and its contents are still visbile on top of the button. (the button is shown behind the dockpanel due to the z order).
I guess I could toggle the visibility of the dock panel at the same time (to be the reverse of the button) but I was hoping to avoid that.
I would bind the DockPanel's Visibility to ShowAboutBox as well, but using an inverse converter. I have a bunch of handy little converters like this created for just this type of scenario:
<Grid>
<Button Visibility="{Binding ShowAboutBox, Converter={StaticResource BoolToVisConverter}}">About My App</Button>
<DockPanel Visibility="{Binding ShowAboutBox, Converter={StaticResource BoolToInverseVisConverter}}"></DockPanel>
</Grid>
And the basic converter (could be expanded to support nullables, etc):
public class BooleanToInverseVisibilityConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
return (bool) value ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
return null;
}
}
Your ZIndex trick isn't working because the button also has a zindex of 0 (since it is first in the collection). You would need to explicitly change the button's ZIndex to somehting higher than 0 for the DockPanel to appear on top of it.
That said, the correct solution here is to just toggle the button's Visibility property between Hidden & Visible, not changing ZIndex at all.
You can use the generic BooleanConverter here and declare True and False value accordingly.

why don't I get any fired converter?

I have radio button and I want to define binding between the radio button IsChecked state and the visibility some stackpanel so I wrote this convert method:
public class RadioBtnState2Visible : IValueConverter
{
// RadioBtn start => Visible / Hide
public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
{
if( value == null )
return Visibility.Collapsed;
bool visibility = false;
bool.TryParse( value.ToString(), out visibility );
return visibility ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
{
throw new NotImplementedException();
//return ( ( Visibility )value ) == Visibility.Visible ? true : false;
}
}
The xaml is
<local:PageEx.Resources>
<local:RadioBtnState2Visible x:Key="Convert" />
</local:PageEx.Resources>
<RadioButton x:Name="MyRadioBtn1" GroupName="group1" />
<RadioButton x:Name="MyRadioBtn2" GroupName="group1" />
<StackPanel Visibility="{Binding ElementName=MyRadioBtn1, Path=IsChecked, Converter={StaticResource Convert}}" />
Now, I dont see any convert fire - i dont see that the application stops on the breakpoint that i set on the first line of the convert method.
This is a duplicate of your previous question, already answered. Here is the answer again:
I got your code working in a test project with one minor change. I made the converter a page resource with the following syntax:
<UserControl.Resources>
<local:RadioBtnState2Visible x:Key="Convert" />
</UserControl.Resources>
I should also mention that I had to actually put something in the stackpanel as well to see the change as by default it collapses to nothing :) I assume you actually have content in your real stackpanel.
Just to explain what is happening here. By adding "local:" to the resource declaration you are actually enclosing an instance of a Resource, and not changing the current resource. Referencing it by "Convert" does not work because it cannot find the resource where it expects to find it.
FYI there is BooleanToVisibilityConverter converter available already:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter1" />
</Window.Resources>

ListBox Disabled state in Silverlight 4

So I'm styling a ListBox and I've got to the part where I need to do a greyed out style when the ListBox is disabled. However when I look a the states tab in Blend, there's only Validation States present - no sign of the usual Common States which include the Disabled state.
I tried creating a vanilla project with no custom styles and just a ListBox and the same thing happens. My question is, how do I go about styling a disabled state for a ListBox? Am I missing something obvious??
First tried the simple approach: Edit the ListBoxItem template, rather than the List box. It is the items that are displayed in disabled state, not the listbox.
In blend:
"Edit Additional Templates" > "Edit Generated Item Container (ItemContainerStyle)" > Edit a copy.
As a test I forced the background colour to red in the disabled state (see picture below). The background colour is normally derived from the parent list. The XAML is too big to list here.
An item container in a listbox consists of a grid containing 3 rectangles (to give the border colour effects) and a content container to hold the actual item content.
fillcolor
fillcolor2
contentPresenter
FocusVisualElement
Obvious problem... all the white-space under the items. Bah! Must be a better way.
Now try to change the ListBox template instead:
To change the template of the ListBox itself I thought you might be able to bind the background colour of the scrollviewer within the ListView Template to the IsEnabled property of the control. This would require a custom value converter (to convert the IsEnabled bool? to a Brush object), but they are pretty simple to create.
TemplateBinding does not support a convertor, but I found that you can use a normal binding in a template, if you use a RelativeSource:
<ScrollViewer x:Name="ScrollViewer" BorderBrush="Transparent" BorderThickness="0" Background="{Binding IsEnabled, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource Bool2Color}}" Padding="{TemplateBinding Padding}" TabNavigation="{TemplateBinding TabNavigation}">
The result looked like this:
The code for the value convertor is below
public class BoolToColourConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool?)
{
return new SolidColorBrush((value as bool?).Value ? Colors.Red : Colors.Orange);
}
throw new NotImplementedException();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
ListBox is a nested control.
You probably will have to style the ScrollViewer control that holds the ListBoxItem(s).
The following two links explain how to style a ListBox. They are not a direct answer to your question, but they may give you some insight on how it works.
http://www.codeproject.com/KB/expression/ListBoxStylingSilverlight.aspx
http://www.codeproject.com/KB/expression/ListBoxStylingPart2.aspx

Resources