【问题标题】:How to hide the textbox and float up when an item is selected from listview?从列表视图中选择项目时如何隐藏文本框并向上浮动?
【发布时间】:2019-03-25 11:24:30
【问题描述】:

我有一个 WPF 应用程序,其中有某些列表视图项。如图中有 3 个项目,A、B、C。最初,当用户不选择任何项目时,文本框将被隐藏。

TextBox 隐藏时的ListView Items

当用户单击任何项​​目时,我希望显示一个包含该项目描述的文本框。

当列表视图中的项目被选中时,文本框显示

【问题讨论】:

标签: c# wpf


【解决方案1】:

在后面的代码中试试这个(MainWindow.xaml.cs):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace WpfApp7
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private MyViewModel m_MyViewModel;
        public MainWindow()
        {

            InitializeComponent();
            m_MyViewModel = new MyViewModel();
            myGrid.DataContext = MyVM;
        }

        public MyViewModel MyVM
        {
            get
            {
                return m_MyViewModel;
            }
        }
    }

    public class MyViewModel : ViewModelBase
    {
        public List<string> MyCollection
        {
            get
            {
                return new List<string> { "A", "B", "C" };
            }
        }

        private bool isListViewItemSelected;

        public bool IsListViewItemSelected
        {
            get
            {
                return isListViewItemSelected;
            }
            set
            {
                isListViewItemSelected = value;
                RaisePropertyChanged("IsListViewItemSelected");
            }
        }


        private string selectedItem;

        public string SelectedItem
        {
            get { return selectedItem; }
            set
            {
                if (value != selectedItem)
                {
                    selectedItem = value;
                    if (selectedItem == null)
                    {
                        IsListViewItemSelected = false;
                    }
                    else
                    {
                        IsListViewItemSelected = true;
                    }
                    RaisePropertyChanged("SelectedItem");
                    RaisePropertyChanged("SelectedTxtString");
                }
            }
        }

        public string SelectedTxtString
        {
            get
            {
                //return SelectedItem;
                return "\"" + SelectedItem + "\" is selected!";
            }
        }
    }

    public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable
    {

        #region DisplayName

        /// <summary>
        /// Returns the user-friendly name of this object.
        /// Child classes can set this property to a new value,
        /// or override it to determine the value on-demand.
        /// </summary>
        public virtual string DisplayName { get; protected set; }

        #endregion // DisplayName

        #region Debugging Aides

        /// <summary>
        /// Warns the developer if this object does not have
        /// a public property with the specified name. This 
        /// method does not exist in a Release build.
        /// </summary>
        [Conditional("DEBUG")]
        [DebuggerStepThrough]
        public void VerifyPropertyName(string propertyName)
        {
            // Verify that the property name matches a real,  
            // public, instance property on this object.
            if (TypeDescriptor.GetProperties(this)[propertyName] == null)
            {
                string msg = "Invalid property name: " + propertyName;

                if (this.ThrowOnInvalidPropertyName)
                    throw new Exception(msg);
                else
                    Debug.Fail(msg);
            }
        }

        /// <summary>
        /// Returns whether an exception is thrown, or if a Debug.Fail() is used
        /// when an invalid property name is passed to the VerifyPropertyName method.
        /// The default value is false, but subclasses used by unit tests might 
        /// override this property's getter to return true.
        /// </summary>
        protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

        #endregion // Debugging Aides

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Raised when a property on this object has a new value.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raises this object's PropertyChanged event.
        /// </summary>
        /// <param name="propertyName">The property that has a new value.</param>
        protected virtual void RaisePropertyChanged(string propertyName)
        {
            VerifyPropertyName(propertyName);

            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        #endregion // INotifyPropertyChanged Members


        #region IDisposable Members

        /// <summary>
        /// Invoked when this object is being removed from the application
        /// and will be subject to garbage collection.
        /// </summary>
        public void Dispose()
        {
            this.OnDispose();
        }

        /// <summary>
        /// Child classes can override this method to perform 
        /// clean-up logic, such as removing event handlers.
        /// </summary>
        protected virtual void OnDispose()
        {
        }

        #endregion // IDisposable Members

    }
}

这在 MainWindow.xaml 中

<Window x:Class="WpfApp7.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApp7"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">

<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>

<Grid x:Name="myGrid">
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <ListView ItemsSource="{Binding MyCollection, Mode=OneWay}" SelectedItem="{Binding SelectedItem}">

    </ListView>

    <TextBox Grid.Row="1" Text="{Binding SelectedTxtString, Mode=OneWay}" 
             Visibility="{Binding IsListViewItemSelected, Converter={StaticResource BooleanToVisibilityConverter}}"/>

</Grid>

【讨论】:

  • 请注意,无论SelectedItem 是否为空,您的IsListViewItemSelected 始终设置为true。除此之外,在 OneWay 绑定上设置 UpdateSourceTrigger=PropertyChanged(如示例中的 TextBox 的文本和可见性绑定)是没有意义的。 UpdateSourceTrigger 仅在 OneWayToSource Bindings 的 TwoWay 中起作用,与 PropertyChanged 事件无关。
  • 自己写一个 BoolToVisibilityConverter 也是没有意义的。框架中已经有一个。
  • 我是这样写的,因为在问题中没有取消选择所有涉及的 ListViewItems ......但你当然是对的。应该检查 SelectedItem 是否为空...
  • 哦,我不知道 .NET 实现了该转换器...谢谢您的提示!
  • 感谢 cmets 关于 UpdateSourceTrigger!它们真的帮助我理解了绑定过程!
【解决方案2】:

使用数据绑定将文本框的可见性标志绑定到当前选中的ListView Item。

在您的 Controller 或 ViewModel 中为 SelectedItem 实现一个属性

public object SelectedItem { get; set; }

在 ListView 中将其绑定到 SelectedItem 属性

<ListView
    ...
    SelectedItem={Bining Path=SelectedItem}/>

使用第二个属性来确定是否选择了 ListView 项

public Visibility TextBoxVisibility=> SelectedItem != null 
    ? System.Windows.Visibility.Visible 
    : System.Windows.Visibility.Hidden;

在您的 xaml 中将 Visibility 属性绑定到 IsSelected 属性

<TextBox
    ...
    Visibility={Bining Path=TextBoxVisibility}/>

希望这会有所帮助。

【讨论】:

  • 不要忘记为视图模型的 SelectedItem 和 TextBoxVisibility 属性触发属性更改通知。还要考虑根本不使用其他属性,而只需使用绑定转换器将 TextBox 的 Visibility 也绑定到 SelectedItem,或者在 SelectedItem 上使用带有 DataTrigger 的 Style 来设置 Visibility。
  • 是的,没错。在属性内当然必须有一个OnPropertyChanged(nameof(SelectedItem)),否则Ui将不知道值何时发生了变化
  • 不仅是OnPropertyChanged(nameof(SelectedItem)),还有OnPropertyChanged(nameof(TextBoxVisibility)),因为当 SelectedItem 发生变化时必须重新评估 TextBoxVisibility。
  • 我可以在文本框中显示描述,但它总是为文本框留出空间。文本框没有隐藏,只有框内的内容被隐藏。我也想隐藏文本框,并且只有当用户单击该项目时它才应该可见。你能帮忙解决这个问题吗?
猜你喜欢
  • 2013-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-21
  • 2014-03-06
相关资源
最近更新 更多