WPF Binding to a RadioButton GroupName - wpf

I have a dynamic ListView using a DataTemplate as follows:
<ListView.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0,0,0,1" BorderBrush="#ccc">
<RadioButton GroupName="MyRadioButtonGroup">
<StackPanel Orientation="Horizontal" Margin="0,0,0,5" Width="{Binding ActualWidth, ElementName=CheckoutGrid}">
<TextBlock Text="{Binding Path=Test1, StringFormat='{}{0} - '}" />
<TextBlock Text="{Binding Path=Test2, StringFormat='{} test {0} - '}" />
<TextBlock Text="{Binding Path=Test, StringFormat='{} test {0}'}" />
</StackPanel>
</RadioButton>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
I would like to have a button disabled until one of the RadioButton IsChecked:
<RadioButton Padding="15,10" VerticalAlignment="Center">
<RadioButton.Style>
<Style TargetType="RadioButton" BasedOn="{StaticResource styleToggleButton4}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MyRadioButtonGroup, Path=IsChecked}" Value="False">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
<TextBlock FontWeight="SemiBold" FontSize="14" Margin="0">NEXT</TextBlock>
</RadioButton>
So the problem is I do not know how to properly bind to the RadioButton GroupName="MyRadioButtonGroup". You will see in the DataTrigger above I am trying Binding="{Binding ElementName=MyRadioButtonGroup, Path=IsChecked}" Value="False", but that is not working for me since obviously it is a GroupName and not an x:Name.
Any suggestions on how to approach this properly? I would rather want to handle this on the front-end if at all possible.

You could bind your radio button to a command and then use the isChecked as a parameter. Then bind to a boolean value based off that. I think this may be more of a workaround though.
<RadioButton
Command="{Binding MyCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}"
GroupName="radio" />
<RadioButton
Command="{Binding MyCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}"
GroupName="radio" />
Then in code behind or VM, it would require implementing the ICommand Interface and INotifyPropertyChanged
public bool IsChecked
{
get { return isChecked;}
set
{
isChecked = value;
OnPropertyChanged();
}
}
private void OnMyCommand(object obj)
{
if(obj is bool)
{
IsChecked = (bool)obj;
}
}

A group has no IsChecked property that you can bind to.
If you don't have a source property that keeps track of whether there is at least one checked RadioButton and "want to handle this on the front-end" - which I guess means in the view - you could write some code that simply sets the Tag property of the ListView to true/false depending on whether there is a RadioButton selected. It is a one-liner:
private void ListView_Checked(object sender, RoutedEventArgs e) => lv.Tag = true;
<ListView x:Name="lv" ToggleButton.Checked="ListView_Checked">
<ListView.ItemTemplate>
...
<ListView.ItemTemplate>
</ListView>
<RadioButton Padding="15,10" VerticalAlignment="Center">
<RadioButton.Style>
<Style TargetType="RadioButton" BasedOn="{StaticResource styleToggleButton4}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=lv, Path=Tag}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
<TextBlock FontWeight="SemiBold" FontSize="14" Margin="0">NEXT</TextBlock>
</RadioButton>

Related

WPF set default Visibility value when editing

I have Visibility bound to a bool, which works perfectly. However when editing the page the Border is not visible. I have to delete the Visibility Binding, make my changes and redo the Visibility Binding.
I'm pretty sure I saw there is a way to set a "editing default", but I cannot find that link anymore (or remember what it was called). Can someone explain how to set the default to visible so I can see it whilst editing, but not affect it's operation at runtime?
<Border Grid.Column="2" BorderBrush="HotPink" BorderThickness="2" MinHeight="100" MinWidth="100"
Visibility="{Binding ElementName=GenerateWorkOrders, Path=IsChecked, Converter={StaticResource booleanToVisibility}, UpdateSourceTrigger=PropertyChanged}">
<Label Content="Not Visible While Editing"/>
</Border>
The problem is that the default value of IsChecked of GenerateWorkOrders CheckBox is false
If IsChecked have Binding, you can use FallbackValue:
<CheckBox x:Name="GenerateWorkOrders" IsChecked="{Binding SomeProperty, FallbackValue=True}" />
Another way is to avoid the binding, you can use the DesignerProperties.IsInDesignMode Attached Properties that indicate if you in design mode (More inforamtion).
You can use this property in behavior, or in XAML only approach:
<Border Grid.Column="2" BorderBrush="HotPink" BorderThickness="2" MinHeight="100" MinWidth="100">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="Visibility" Value="{Binding ElementName=GenerateWorkOrders, Path=IsChecked, Converter={StaticResource booleanToVisibilityConverter}, UpdateSourceTrigger=PropertyChanged}" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=(componentModel:DesignerProperties.IsInDesignMode)}" Value="true">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Label Content="Not Visible While Editing"/>
</Border>

How to invoke DataTrigger on a Toolbar Button during Validate.HasError

I have implemented the following xaml code to disable a toolbar button when Validation.HasError based on the text entered into the ComboBox based on the UserAccountValidationRule
The core xaml code is shown here:
<telerik:RadComboBox
x:Name="DataProviderComboBox" Width="120" Height="23" IsEditable="True" DataContext="{StaticResource MainWindowViewModel}">
<telerik:RadComboBox.Text>
<Binding Mode="TwoWay" Path="InputString">
<Binding.ValidationRules>
<validationRules:UserAccountValidationRule/>
</Binding.ValidationRules>
</Binding>
</telerik:RadComboBox.Text>
</telerik:RadComboBox>
<telerik:RadButton
Name="ToolbarButton" Width="74" HorizontalAlignment="Left" VerticalAlignment="Top" Content="Button">
<telerik:RadButton.Style>
<Style TargetType="{x:Type telerik:RadButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding (Validation.HasError), ElementName=DataProviderComboBox}" Value="true" >
<Setter Property="IsEnabled" Value="false"/>
</DataTrigger>
</Style.Triggers>
</Style>
</telerik:RadButton.Style>
</telerik:RadButton>
</telerik:RadToolBar>
<Grid>
<telerik:RadButton
Name="OrdinaryButton" Width="74" HorizontalAlignment="Left" VerticalAlignment="Top" Content="Button" Margin="252,26,0,0">
<telerik:RadButton.Style>
<Style TargetType="{x:Type telerik:RadButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding (Validation.HasError), ElementName=DataProviderComboBox}" Value="true" >
<Setter Property="IsEnabled" Value="false"/>
</DataTrigger>
</Style.Triggers>
</Style>
</telerik:RadButton.Style>
</telerik:RadButton>
</Grid>
What I would like is for the DataTrigger in the ToolBarButton to be invoked, but it is not.
I did a check on the validation by creating a second OrdinarryButton, and hooked this up to the validation, and this worked fine. It seems as if the DataTrigger does not work if the button is a toolbar item.
Can anyone explain how to get this to work?
So, as it turns out, if the button is an OrdinaryButton control, then the DataTrigger will be invoked and the button will be disabled on Validation.HasError = true via the xaml code below:
<Grid>
<telerik:RadButton
Name="OrdinaryButton" Width="74" HorizontalAlignment="Left" VerticalAlignment="Top" Content="Button" Margin="252,26,0,0">
<telerik:RadButton.Style>
<Style TargetType="{x:Type telerik:RadButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding (Validation.HasError), ElementName=DataProviderComboBox}" Value="true" >
<Setter Property="IsEnabled" Value="false"/>
</DataTrigger>
</Style.Triggers>
</Style>
</telerik:RadButton.Style>
</telerik:RadButton>
</Grid>
However, if the button control is placed inside a ToolbarButton, the same xaml code will not disable the Toolbar button:
<telerik:RadComboBox
x:Name="DataProviderComboBox" Width="120" Height="23" IsEditable="True" DataContext="{StaticResource MainWindowViewModel}">
<telerik:RadComboBox.Text>
<Binding Mode="TwoWay" Path="InputString">
<Binding.ValidationRules>
<validationRulesParameterPass:UserAccountValidationRule/>
</Binding.ValidationRules>
</Binding>
</telerik:RadComboBox.Text>
</telerik:RadComboBox>
<telerik:RadButton
Name="ToolbarButton" Width="74" HorizontalAlignment="Left" VerticalAlignment="Top" Content="Button">
<telerik:RadButton.Style>
<Style TargetType="{x:Type telerik:RadButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding (Validation.HasError), ElementName=DataProviderComboBox}" Value="true" >
<Setter Property="IsEnabled" Value="false"/>
</DataTrigger>
</Style.Triggers>
</Style>
</telerik:RadButton.Style>
</telerik:RadButton>
</telerik:RadToolBar>
I find this very peculiar, and it might be a previously undiscovered bug? If anyone knows whether this is expected behavior or not, and has a reason for the observed behavior, please feel free to post.
In the meantime, I spent some time developing an acceptable workaround.
In this case I modified the <validationRules:UserAccountValidationRule/> to take a parameter that passes a single boolean IsEnabled property:
<Binding.ValidationRules>
<validationRulesParameterPass:UserAccountValidationRule>
<validationRulesParameterPass:UserAccountValidationRule.AccountValidationParameter>
<validationRulesParameterPass:AccountValidationParameter IsEnabled="{Binding IsButtonEnabled, Source={StaticResource MainWindowViewModel}}" />
</validationRulesParameterPass:UserAccountValidationRule.AccountValidationParameter>
</validationRulesParameterPass:UserAccountValidationRule>
</Binding.ValidationRules>
I also binded the IsButtonEnabled dependency property property to the ToolBar Button item's IsEnabled property.
Then, inside the UserAccountValidationRule, based on whether the value is valid or not, the IsButtonEnabled property will be set to true or false. As this DependencyProperty is connected to the Toolbar Button's, if the validation sets this true, the button's IsEnabled property will also be set to true, and vice versa.
public class UserAccountValidationRule : ValidationRule
{
private AccountValidationParameter _accountValidationParameter;
public UserAccountValidationRule()
{
}
public AccountValidationParameter AccountValidationParameter
{
get { return _accountValidationParameter; }
set { _accountValidationParameter = value; }
}
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
if ( !string.IsNullOrEmpty(value as string) && value as string == "good")
{
AccountValidationParameter.IsEnabled = true;
return new ValidationResult(true, null);
}
else
{
AccountValidationParameter.IsEnabled = false;
return new ValidationResult(false, "bad string.");
}
}
}
Problem solved.

How to apply style to Listbox Item based on Property value in WPF

<ListBox ItemsSource="{Binding Customers}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="1" x:Name="BackgroundGrid">
<TextBlock Text="{Binding CustomerName}" />
<TextBlock Text="{Binding CustomerId}" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding CustomerId}" Value="9-3453"><Setter TargetName="BackgroundGrid" Property="Background" Value="Red"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In the above code, I need to provide DataTrigger's value based on property value instead of hard code the value.
Thanks in advance,
Dinesh
Supposed your DataTrigger's value based on property CustomerNumber. Then you add another property for binding, like this:
public bool CustomerIdMatchs
{
get{
return CustomerNumber==CustomerId;
}
}
Then you bind CustomerIdMatchs instead of CustomerId, like this:
<DataTrigger Binding="{Binding CustomerIdMatchs}" Value="true">
<Setter TargetName="BackgroundGrid" Property="Background" Value="Red"/>
</DataTrigger>

How to set the Control Visibilty of the Second Control depending on the Binding Value of the first

I have a Custom Wpf Control i.e. combobox:WpfTwComboBox. I want to set the visibility using a property called DisableProviderSelector.
The usual use of triggers is not helping. The scenario here is when the above control i.e. WindowsFormsHost is made visible or collapsed, I want the opposite to happen to the below custom control.
<StackPanel Grid.Row="3" Grid.Column="2" Height="25" Orientation="Horizontal"
Width="375" HorizontalAlignment="Left">
<WindowsFormsHost Height="25" Width="375">
<WindowsFormsHost.Style>
<Style TargetType="WindowsFormsHost">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=DisableProviderSelector}" Value="true">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=DisableProviderSelector}" Value="false">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</WindowsFormsHost.Style>
<commonControls:ProviderSelectorControl RequiredLevel="Save" ModifiedByUser="providerSelectorControl1_ModifiedByUser" x:Name="providerSelectorControl1"/>
</WindowsFormsHost>
<combobox:WpfTwComboBox x:Name="PortalProviderSelector"
SelectedValue="{Binding SelectedPortalProvider}"
ItemsSource="{Binding Path=PortalProvidersCollection}"
DisplayMemberPath="FullName" Width="350" Height="25"
RequiredLevelFlag="Save">
</combobox:WpfTwComboBox>
</StackPanel>
Can anyone please help me on how to set the visibility here?
So DisableProviderSelector is a bool when set to True WindowsFormsHost needs to be Collapsed and ComboBox needs to be Visible. Reverse when bool is false.
So as far as the ComboBox is concerned if bool is True it's Visible and when False it's Collapsed. Thus just bind the ComboBox directly to the Property and use a BooleantoVisibilityConverter
xaml:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
...
<combobox:WpfTwComboBox x:Name="PortalProviderSelector"
Width="350"
Height="25"
DisplayMemberPath="FullName"
ItemsSource="{Binding Path=PortalProvidersCollection}"
RequiredLevelFlag="Save"
Visibility="{Binding DisableProviderSelector,
Converter={StaticResource BooleanToVisibilityConverter}}"
SelectedValue="{Binding SelectedPortalProvider}" />

Dynamically change the content of of control based on a value

I want to achieve the following behavior:
Depending on a value use a different datatemplate:
<DataTemplate x:Key="cardTemplate2">
<Border x:Name="container">
.....
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ShowSecondDT}" Value="True">
<Setter Property="Child" TargetName="container">
<Setter.Value>
<StackPanel Orientation="Vertical" >
</StackPanel>
</Setter.Value>
</Setter>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
The application fails claiming that Setter Property="Child" is null...
Another information is that this Datatemplate in the resource of a control: (devexpress gris)
<dxg:GridControl xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
x:Name="gridTitulaire" DataSource="{Binding Contacts}" Width="600" >
<dxg:GridControl.Resources>
<DataTemplate x:Key="cardTemplate2">
<Border x:Name="container">
<StackPanel Orientation="Horizontal" >
</StackPanel>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding isTitulairePrincipal}" Value="True">
<Setter Property="Child" TargetName="container">
<Setter.Value>
<StackPanel Orientation="Vertical" >
</StackPanel>
</Setter.Value>
</Setter>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</dxg:GridControl.Resources>
<dxg:GridControl.Columns>
<dxg:GridColumn FieldName="first_name"/>
<dxg:GridColumn FieldName="last_name"/>
</dxg:GridControl.Columns>
<dxg:GridControl.View>
<dxg:CardView x:Name="view" ShowGroupedColumns="True" CardTemplate="{DynamicResource cardTemplate2}" />
</dxg:GridControl.View>
</dxg:GridControl>
Any idea ?
Thanks
Jonathan
Define two separate data templates (call them CardTemplateV for the vertical one, and CardTemplateH for the horizontal one, for example), and set the CardTemplateSelector to a selector object that checks the discriminating field.
Example:
class MyTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var cardData = item as CardData;
if (cardData == null) return null;
var dataObject = cardData.DataContext as YourDataType;
if (dataObject == null) return null;
if (dataObject.isTitulairePrincipal)
return (DataTemplate)App.Current.FindResource("CardTemplateV");
else
return (DataTemplate)App.Current.FindResource("CardTemplateH");
}
}
In the XAML add the selector to the resource dictionary and reference it from the grid:
<Window.Resources>
<local:YourTemplateSelector x:Key="MyTemplateSelector"/>
</Window.Resources>
...
<dxg:CardView
x:Name="view"
ShowGroupedColumns="True"
CardTemplateSelector="{StaticResource MyTemplateSelector}"/>
...

Resources