Wpf 当UserControl的文本框为空时禁用菜单项

Wpf 当UserControl的文本框为空时禁用菜单项,wpf,binding,textbox,user-controls,menuitem,Wpf,Binding,Textbox,User Controls,Menuitem,在我的主窗口中有一个菜单项和一个用户控件。如果UserControl中的文本框之一分别为空/非空,我想禁用/启用MenuItem 给定一个名为ContactDetails的UserControl和一个名为ContactNameTextBox的TexBox,下面是我的菜单项的xaml代码: <MenuItem x:Name="DeleteContact" Header="Delete Contact" IsEnabled="{Binding Ele

在我的主
窗口中
有一个
菜单项
和一个
用户控件
。如果
UserControl
中的
文本框之一分别为空/非空,我想禁用/启用
MenuItem

给定一个名为
ContactDetails
UserControl
和一个名为
ContactNameTextBox
TexBox,下面是我的
菜单项的xaml代码:

<MenuItem x:Name="DeleteContact" 
          Header="Delete Contact" 
          IsEnabled="{Binding ElementName=ContactDetails.ContactNameTextBox,Path=Text.Length, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>


由于某些原因,
MenuItem
始终保持启用状态。我缺少什么?

您正在绑定文本的长度,但需要从长度到布尔值的转换器,因为IsEnabled属性需要布尔值

public class NumToBoolConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter,    System.Globalization.CultureInfo culture) 
    { 
       if (value!=null && value is int ) 
       {
          var val = (int)value; 
          return (val==0) ? false : true; 
       } 
       return null; 
    } 


    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
       if (value!=null && value is bool ) 
       { 
         var val = (bool)value; return val ? 1 : 0;
       } 
       return null; 
    }
}
为此和资源添加本地xmlns

 xmlns:local="clr-namespace:YourNamespace"
这是对converter类的引用

<local:NumToBoolConverter x:Key="NumToBoolConverter"/>
这可以是您的最终菜单项定义:

        <MenuItem x:Name="DeleteContact" 
                  Header="Delete Contact"
                  IsEnabled="{Binding ElementName=ContactDetails.ContactNameTextBox,
                                      Path=Text.Length, 
                                      Converter={StaticResource NumToBoolConverter},
                                      Mode=TwoWay, 
                                      UpdateSourceTrigger=PropertyChanged}"/>

您的绑定有几个问题。首先,您指定了一个双向绑定。这意味着您希望回写文本框中的“length”属性。因为它是只读的,所以你不能

通常情况下,您会得到一个错误:

双向或单向ToSource绑定无法在只读服务器上工作 类型为“System.String”的属性“Length”

奇怪的是,在那之后绑定就开始工作了。但这确实不是正确的方法。NET的神奇之处在于允许将0解释为“false”。但这不是一个安全的约束。正如Olaru在回答中所说,length属性是一个整数,IsEnabled字段正在寻找布尔值。如果要绑定到“可见性”属性,该怎么办

那么,处理这个问题的最佳方法是什么呢?转换器绝对是一种选择,在许多情况下是最佳选择。转换器的优点是可以在类似情况下重复使用。我们有一个我们经常使用的转换器库。奥拉鲁已经描述了如何做到这一点,所以我不会重复他已经说过的话

但在某些情况下,了解不同的方法是有益的。datatrigger将允许您执行与转换器相同的操作。这是一种单向绑定。这里有一个例子

<MenuItem x:Name="DeleteContact"  Header="Delete Contact">
   <MenuItem.Style>
       <Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}">
         <Setter Property="MenuItem.IsEnabled" Value="true"/>
         <Style.Triggers>
           <DataTrigger Binding="{Binding Text.Length, ElementName=ContactNameTextBox}" Value="0">
               <Setter Property="MenuItem.IsEnabled" Value="false"/>
           </DataTrigger>
         </Style.Triggers>
       </Style>
    </MenuItem.Style>
  </MenuItem>

不需要代码

关于转换器和数据触发器的利弊有很多争论。但最重要的是要知道有不止一种方法可以满足你的要求

<MenuItem x:Name="DeleteContact"  Header="Delete Contact">
   <MenuItem.Style>
       <Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}">
         <Setter Property="MenuItem.IsEnabled" Value="true"/>
         <Style.Triggers>
           <DataTrigger Binding="{Binding Text.Length, ElementName=ContactNameTextBox}" Value="0">
               <Setter Property="MenuItem.IsEnabled" Value="false"/>
           </DataTrigger>
         </Style.Triggers>
       </Style>
    </MenuItem.Style>
  </MenuItem>