问题
I have a Button
within my app whose "enabledness" I have bound to whether a TextBox
is empty as so:
<Button Content="Go"
IsEnabled="{Binding Text,
Converter={StaticResource EnableIfStringNotEmptyDataSource},
ElementName=MyTextbox}"/>
(implementation of EnableIfStringNotEmptyDataSource
omitted for brevity).
This automatically changes the state when the TextBox
's text changes.
What would be the most elegant way of binding a property in the same manner to whether two textboxes are both empty or not?
回答1:
Edit: For silverlight this is probably the cleanest it gets:
<TextBox Text="{Binding TB1Text, Mode=TwoWay}" />
<TextBox Text="{Binding TB2Text, Mode=TwoWay}"/>
<Button Content="Lorem Ipsum" IsEnabled="{Binding ButtonIsEnabled}"/>
private string _TB1Text;
public string TB1Text
{
get { return _TB1Text; }
set
{
if (_TB1Text != value)
{
_TB1Text = value;
PropertyChanged.Notify(() => this.TB1Text);
PropertyChanged.Notify(() => this.ButtonIsEnabled);
}
}
}
private string _TB2Text;
public string TB2Text
{
get { return _TB2Text; }
set
{
if (_TB2Text != value)
{
_TB2Text = value;
PropertyChanged.Notify(() => this.TB2Text);
PropertyChanged.Notify(() => this.ButtonIsEnabled);
}
}
}
public bool ButtonIsEnabled
{
get { return !(String.IsNullOrEmpty(TB1Text) && String.IsNullOrEmpty(TB2Text)); }
}
(PropertyChanged.Notify
is just an extension method which raises the event without the need to pass around strings)
Would not use a binding but a MultiDataTrigger
:
<TextBox Name="tb1"/>
<TextBox Name="tb2"/>
<Button Content="Lorem Ipsum">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Text, ElementName=tb1}" Value="{x:Static sys:String.Empty}"/>
<Condition Binding="{Binding Text, ElementName=tb2}" Value="{x:Static sys:String.Empty}"/>
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="False"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
By the way, you do not need a converter for your one TextBox case:
<Button Content="Lorem Ipsum" IsEnabled="{Binding Text.Length,
ElementName=MyTextBox}"/>
回答2:
I do not understand why people insist on writing code when this is doable completely in XAML. To do this, you'll need the Blend SDK (for Windows Phone or .NET 4, whichever platform you're targeting). Add references to Microsoft.Expression.Interactions.dll and System.Windows.Interactivity.dll. Then you just need to declare change the button's enabled state (ChangePropertyAction
) whenever the text changes (EventTrigger EventName="TextChanged"
). You'll need two changes: one to enable the button when both TextBoxes have text and another to disable the button when one TextBox lacks text. The only "trick" here is declaring an empty string resource so you have something against which you can compare the text values.
The XAML:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:System="clr-namespace:System;assembly=mscorlib"
x:Class="SilverlightApplication4.MainPage">
<UserControl.Resources>
<System:String x:Key="EmptyString"></System:String>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox x:Name="textBox1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:Interaction.Behaviors>
<ei:ConditionBehavior>
<ei:ConditionalExpression>
<ei:ComparisonCondition LeftOperand="{Binding Text, ElementName=textBox1}" RightOperand="{StaticResource EmptyString}"/>
</ei:ConditionalExpression>
</ei:ConditionBehavior>
</i:Interaction.Behaviors>
<ei:ChangePropertyAction TargetObject="{Binding ElementName=button}" PropertyName="IsEnabled"/>
</i:EventTrigger>
<i:EventTrigger EventName="TextChanged">
<i:Interaction.Behaviors>
<ei:ConditionBehavior>
<ei:ConditionalExpression>
<ei:ComparisonCondition LeftOperand="{Binding Text, ElementName=textBox1}" Operator="NotEqual" RightOperand="{StaticResource EmptyString}"/>
<ei:ComparisonCondition LeftOperand="{Binding Text, ElementName=textBox2}" Operator="NotEqual" RightOperand="{StaticResource EmptyString}"/>
</ei:ConditionalExpression>
</ei:ConditionBehavior>
</i:Interaction.Behaviors>
<ei:ChangePropertyAction TargetObject="{Binding ElementName=button}" PropertyName="IsEnabled" Value="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<TextBox x:Name="textBox2" Grid.Row="1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:Interaction.Behaviors>
<ei:ConditionBehavior>
<ei:ConditionalExpression>
<ei:ComparisonCondition LeftOperand="{Binding Text, ElementName=textBox2}" RightOperand="{StaticResource EmptyString}"/>
</ei:ConditionalExpression>
</ei:ConditionBehavior>
</i:Interaction.Behaviors>
<ei:ChangePropertyAction TargetObject="{Binding ElementName=button}" PropertyName="IsEnabled"/>
</i:EventTrigger>
<i:EventTrigger EventName="TextChanged">
<i:Interaction.Behaviors>
<ei:ConditionBehavior>
<ei:ConditionalExpression>
<ei:ComparisonCondition LeftOperand="{Binding Text, ElementName=textBox1}" Operator="NotEqual" RightOperand="{StaticResource EmptyString}"/>
<ei:ComparisonCondition LeftOperand="{Binding Text, ElementName=textBox2}" Operator="NotEqual" RightOperand="{StaticResource EmptyString}"/>
</ei:ConditionalExpression>
</ei:ConditionBehavior>
</i:Interaction.Behaviors>
<ei:ChangePropertyAction TargetObject="{Binding ElementName=button}" PropertyName="IsEnabled" Value="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<Button x:Name="button" Grid.Row="2" Content="Go" IsEnabled="False"/>
</Grid>
</UserControl>
Edit: This will work in WPF, Silverlight, and WP7 (and probably WinRT when it's released). For WP7, you need Windows Phone SDK 7.1 which includes the Expression Blend SDK for Windows Phone 7.
回答3:
I would expect that you have bound your TextBoxs each to a class string property. In which case you then bind the button enable to a boolean property that performs the test on the text properties in the getter and returns true/false accordingly.
e.g. in your ViewModel (assuming MVVM with Silverlight)
public class ViewModel
{
//note INotifyPropertyChanged functionality ommitted for brevity.
public string TextBox1{get;set;}
public string TextBox2{get;set;}
public bool EnableButton
{
get{ return (!(TextBox1.IsNullOrEmpty() || TextBox2.IsNullOrEmpty());
}
}
来源:https://stackoverflow.com/questions/8123948/cleanest-way-to-bind-a-buttons-visibility-to-the-contents-of-two-textboxes