【问题标题】:WPF ListBox custom itemWPF ListBox 自定义项
【发布时间】:2014-09-23 02:14:27
【问题描述】:

我希望在 ListBox 中有一个“自定义”项,以便用户可以输入除预设可选值之外的自定义值。

这是我的 XAML 代码:

        <ListBox SelectedValue="{Binding SomeValue}"
                 SelectedValuePath="Tag"
                 Style="{StaticResource HorizontalRadioButtonList}">
            <!-- style from http://stackoverflow.com/a/4120034/1813487 -->
            <ListBoxItem Tag="10" 
                     Content="10"/>
            <ListBoxItem Tag="20" 
                     Content="20"/>
            <ListBoxItem Tag="30" 
                     Content="30"/>
            <ListBoxItem x:Name="CustomListBoxItem">
                <TextBox Text="{Binding ElementName=CustomListBoxItem, 
                                        Mode=OneWayToSource, 
                                        UpdateSourceTrigger=PropertyChanged, 
                                        Path=Tag}"/>
            </ListBoxItem>
        </ListBox>
        <TextBlock Text="{Binding SomeValue}"/>

如何在用户在 TextBox 中输入内容后立即更新 SomeValue?目前 ListBox 没有检测到 Tag 发生了变化,也没有更新 SomeValue。

【问题讨论】:

  • @MarcelB 这没有任何意义。 SomeValue 是我的 DataContext 的一个属性。 UniqueValue 是最后一个 ListBoxItem 的名称。否则,{Binding UniqueValue.Tag},如果它有效,就相当于我在那里的。
  • 是的,你是对的。我在上面混了一些东西……对不起。

标签: c# wpf xaml data-binding listbox


【解决方案1】:

我认为您可以使用附加到 TextBox 的行为来实现这一点,您可以在其中签署 TextChanged 事件,并且每次触发它时,您都可以将 ListBoxItem 的标签设置为 TextBox 的文本。

我做了类似的事情,但使用的是 Microsoft.Expression.Interactivity:

<ListBoxItem x:Name="UniqueValue" Tag="40">
    <TextBox x:Name="TextBox" Text="40">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="TextChanged">
                <ei:ChangePropertyAction PropertyName="Tag"
                                                             TargetObject="{Binding ElementName=UniqueValue}"
                                                             Value="{Binding Text,
                                                                             ElementName=TextBox}" />

                <ei:ChangePropertyAction PropertyName="SomeValue"
                                                             TargetObject="{Binding}"
                                                             Value="{Binding Text,
                                                                             ElementName=TextBox,
                                                                             Converter={StaticResource StringToIntConverter}}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </TextBox>
</ListBoxItem>

基本上,每次更改文本时,属性 Tag 都会将其值设置为写入的文本,然后(为了保持 ListBoxItem 的选择)viewmodel 的属性 SomeValue 将其值设置为相同的文本。

命名空间:

    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

需要组件:

System.Windows.Interactivity
Microsoft.Expression.Interactions

【讨论】:

  • 这基本上等同于为TextChanged编写事件处理程序并在C#代码中做同样的事情吗?
  • 是的,但是这样就不需要后面的代码了。就像我说的,你仍然可以创建一个行为来做到这一点。
  • 我对这种方法的问题是,通过直接在 ViewModel 上设置属性,它绕过了绑定,因此在原始 SomeValue 绑定上设置的所有转换器、验证器等都不会生效。
  • 好的,我假设 SomeValue 是一个整数,所以它需要在设置之前转换字符串标签。我在设置 SomeValue 之前编辑并放置了一个转换器。
【解决方案2】:

我是这样做的,这也不是完美的解决方案:

XAML:

<ListBox SelectedValue="{Binding SomeValue}"
             SelectedValuePath="Tag"
             Style="{StaticResource HorizontalRadioButtonList}"
             x:Name="CustomListBox">
        <!-- ...items... -->
        <ListBoxItem x:Name="CustomListBoxItem">
            <TextBox Text="{Binding ElementName=CustomListBoxItem, 
                                    Mode=OneWayToSource, 
                                    UpdateSourceTrigger=PropertyChanged, 
                                    Path=Tag}"
                     TextChanged="UpdateCustomValue"
                     x:Name="CustomTextBox"/>
        </ListBoxItem>
    </ListBox>
    <TextBlock Text="{Binding SomeValue}"/>

代码:

private void UpdateUniqueValue(object sender, TextChangedEventArgs e)
{
    var listBox = sender == CustomTextBox? CustomListBox: null;
    if (listBox != null)
    {
        var textBox = (TextBox) sender;
        try // so that invalid values are not allowed
        {
            listBox.SelectedValue = textBox.Text;
        }
        catch
        {
            textBox.Text = listBox.SelectedValue.ToString();
        }
    }
}

这是一种解决方法,也没有考虑验证器,但至少不允许输入无效值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-26
    • 1970-01-01
    • 1970-01-01
    • 2016-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多