将WPF的IsEnabled属性绑定到Listbox的SelectedItem上。

4
使用MVVM模式,我已经成功地将一个ObservableCollection<string>绑定到了一个ListBox上,以RadioButton的形式显示出值。该控件的行为与预期完全一致。
现在我有一个问题,涉及到一些绑定到这个ListBox的TextBoxes:当ListBox中的SelectedItem等于特定值(例如ValueForEnabled)时,我希望TextBoxes被启用,否则它们应该被禁用。
我知道我必须绑定到ListBox(名为lbSource)的SelectedItem,但具体如何实现呢?
我想要类似于以下的代码(伪代码):
<TextBox  ...

    IsEnabled="{Binding ElementName=lbSource, Path=SelectedItem='ValueForEnabled',
                Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" 
                ...            
/>
4个回答

7

好的!我找到了另一种方法解决它!对于任何想知道的人:

<TextBox 
...
usual property definitions
...
                      >
                <TextBox.Style>
                    <Style>
                        <Setter Property="TextBox.IsEnabled" Value="False"/>
                        <Style.Triggers>                              
                            <DataTrigger Binding="{Binding ElementName=lbSource , Path=SelectedItem}" Value="ValueForEnabled">
                                <Setter  Property="TextBox.IsEnabled" Value="true"/>
                            </DataTrigger>                           
                        </Style.Triggers>                       
                    </Style>                   
                </TextBox.Style>
            </TextBox>

3

我个人认为,如果您正在使用MVVM,则应将代码保留在ViewModel中。因此,如果您的VM如下所示:

public class MyViewModel
{
  public ObservableCollection<string> myColl {get;set;}
  public string SelectedString {get;set;}

  public bool IsEnabled
  {
     get { return SelectedString == "Desired string value";}
  }
}

接下来,您只需将文本框的IsEnabled属性绑定到ViewModel上的IsEnabled属性即可。

我这么说的原因是您的要求可能会更改,例如何时启用文本框,如果您以这种方式执行,则无需触及视图(其中不应存在代码/逻辑)

现在,在您的视图中执行此操作即可。

<TextBox IsEnabled={Binding IsEnabled} Text={Binding SelectedString}/>

希望我理解了您的问题并且这能有所帮助。

1
起初我想,“为什么要这样做”?因为你建议不要在XAML中放置任何“逻辑”(就像我正在做的那样),而是在VM中处理。启用(或禁用)文本框与XAML紧密耦合(我的意思是,如果我想要“调整” UI 元素的属性,我会在XAML中操作,这样我就可以看到是否已经设置了某些内容)。所以(根据我所理解的),您正在将解决方案转移到同一领域中的另一个位置!唯一让我不满意的是让VM代码“混杂”在一起。谢谢Jose! - Savvas Sopiadis
你的虚拟机应该包含所有代码,而视图应将其转换为某些可见表示(有时使用转换器)。这可以是禁用、隐藏、弹出某种通知。您的虚拟机不应关心那是什么,但它应该知道有一个特定的状态。然后,视图绑定到该属性。视图中最接近代码的部分应该是转换器,因为这将从您的 VM 解耦视图。例如,布尔值到可见性转换器允许您的 VM 具有布尔属性,同时视图将该布尔值转换为“折叠”或“可见”。 - Jose
你的视图基本上只是一个可视化翻译器。它将列表翻译成组合框、列表框或列表视图。将字符串、整数、长整型和日期时间翻译成文本框。当然,你的视图和 VM 是“耦合”的,但只是在视图需要知道它正在翻译什么的意义上。你的视图需要知道 ViewModel,但 ViewModel 不应该知道你的视图,否则 MVVM 带来的关注点分离就会严重受损。我应该能够将一个 VM 弹出到 Winforms 应用程序中,而不需要任何代码更改,只需重新绑定到新的所需视图,但 WPF 更容易 :) - Jose
但是,没有一种正确的方法,许多方法都可以解决问题,只是有些方法比其他方法更易于维护。 :) - Jose

2

一种处理这个问题的方法是将列表框中的字符串转换为布尔类型,然后传递到IsEnabledProperty属性中...

首先,创建一个实现IValueConverter接口的类,例如:

public class StringToBoolConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null)
            return false;

        string keyword = value.ToString();
        if (keyword.Equals(parameter.ToString(), StringComparison.CurrentCultureIgnoreCase))
            return true;
        return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

注意,您不需要实现ConvertBack方法吗?这是因为您只需要将字符串转换为布尔值,而不是反过来...
所以您可以在xaml中声明转换器的实例,例如:
<Window
    ...
    xmlns:local="clr-namespace:WpfApplication1">

    <Window.Resources>
        <local:StringToBoolConverter x:Key="stringToBoolConverter" />
    </Window.Resources>

最后,您可以将TextBox绑定到ListBox的SelectedValue,如下所示:
<TextBox Grid.Row="0" Width="90" Height="30" 
         IsEnabled="{Binding ElementName=lbSource, Path=SelectedValue, Converter={StaticResource stringToBoolConverter}, ConverterParameter=ValueForEnabled}">
</TextBox>

注意:此方法仅适用于 ListBox 包含字符串,并且您可以确保 SelectedValue 属性是字符串类型...

有趣的方法! 我想避免使用转换器(可能听起来很傻,但我觉得我的代码有点……四散 - 但如果不能用其他方式完成,我当然会使用它们)。 快速回答是加分项! 非常感谢! - Savvas Sopiadis

0

这是我对上面答案的版本。在我的情况下,如果没有选择,我想禁用整个GroupBox控件。

在这种情况下的关键是使用{x:Null}来检测没有选择的情况。因此,样式默认将IsEnabled设置为True,当SelectedItemnull时,触发器将其设置为False

                <GroupBox.Style>
                    <Style>
                        <Setter
                            Property="GroupBox.IsEnabled"
                            Value="True"
                            />
                        <Style.Triggers>
                            <DataTrigger
                                Binding="{Binding ElementName=GroupList,
                                                  Path=SelectedItem}"
                                Value="{x:Null}"
                                >
                                <Setter
                                    Property="GroupBox.IsEnabled"
                                    Value="False"
                                    />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </GroupBox.Style>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接