WPF切换数据模板中ui元素的可见性
本文关键字:ui 元素 可见性 数据 WPF | 更新日期: 2023-09-27 18:06:54
我有一个DataTemplate
定义如下
<DataTemplate x:Key="PasswordViewerTemplate">
<StackPanel>
<TextBlock Text="{Binding PasswordChar, ElementName=this}"
Visibility="Visible" />
<TextBox Text="{Binding PasswordText}"
Visibility="Collapsed" />
</StackPanel>
</DataTemplate>
我希望能够切换TextBlock
和TextBox
的可见性每次用户点击StackPanel
。我尝试在StackPanel
上设置MouseLeftButtonUp
事件处理程序,但这会抛出异常
Object reference not set to an instance of an object
是否有其他方法来实现这一点?也许在XAML本身使用触发器?
同样,这可能是相关的。上面的模板是模板选择器应用于ListBox
的两个模板之一。ListBox
本身在Grid
中,两个模板都在Grid.Resources
部分中定义。
编辑1
我尝试按如下方式设置事件
<StackPanel MouseLeftButtonUp="OnPasswordViewerMouseLeftButtonUp">
...
</StackPanel>
private void OnPasswordViewerMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var sp = sender as StackPanel;
if( ( sp == null ) || ( sp.Children.Count != 2 ) ) {
return;
}
var passwordText = sp.Children[0] as TextBlock;
var plainText = sp.Children[1] as TextBox;
if( ( passwordText == null ) || ( plainText == null ) ) {
return;
}
passwordText.Visibility = ( passwordText.Visibility == Visibility.Visible ) ?
Visibility.Collapsed : Visibility.Visible;
plainText.Visibility = ( plainText.Visibility == Visibility.Visible ) ?
Visibility.Collapsed : Visibility.Visible;
}
解决方案之一是将TextBox
和TextBlock
的可见性绑定到类的属性,该类用于StackPanel
的DataContext
。下面是一个示例实现:
Xaml代码:
<Grid>
<Grid.Resources>
<DataTemplate x:Key="PasswordViewerTemplate">
<StackPanel PreviewMouseUp="StackPanel_PreviewMouseUp">
<TextBlock Text="{Binding Path=PasswordChar}"
Visibility="{Binding Path=TextBlockVisibility}" />
<TextBox Text="{Binding Path=PasswordText}"
Visibility="{Binding Path=TextBoxVisibility}" />
</StackPanel>
</DataTemplate>
</Grid.Resources>
<ListBox x:Name="lbox" ItemTemplate="{StaticResource ResourceKey=PasswordViewerTemplate}" ItemsSource="{Binding}"/>
</Grid>
c#代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ObservableCollection<Some> items = new ObservableCollection<Some>();
for (int i = 0; i < 10; i++)
{
items.Add(new Some(string.Format("passwordChar {0}", i + 1), string.Format("passwordText {0}", i + 1), Visibility.Visible, Visibility.Collapsed));
}
this.lbox.ItemsSource = items;
}
private void StackPanel_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
Some some = (sender as StackPanel).DataContext as Some;
some.TextBlockVisibility = ToggleVisibility(some.TextBlockVisibility);
some.TextBoxVisibility = ToggleVisibility(some.TextBoxVisibility);
}
private Visibility ToggleVisibility(Visibility visibility)
{
return visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
}
}
public class Some:INotifyPropertyChanged
{
private string _passwordChar;
private string _passwordText;
private Visibility _textBlockVisibility, _textBoxVisibility;
public string PasswordChar { get { return this._passwordChar; } set { this._passwordChar = value; } }
public string PasswordText { get { return this._passwordText; } set { this._passwordText = value; } }
public Visibility TextBlockVisibility
{
get { return this._textBlockVisibility; }
set
{
this._textBlockVisibility = value;
RaisePropertyChanged("TextBlockVisibility");
}
}
public Visibility TextBoxVisibility
{
get { return this._textBoxVisibility; }
set
{
this._textBoxVisibility = value;
RaisePropertyChanged("TextBoxVisibility");
}
}
public Some(string passwordChar, string passwordText, Visibility textBlockVisibility, Visibility textBoxVisibility)
{
this._passwordChar = passwordChar;
this._passwordText = passwordText;
this._textBlockVisibility = textBlockVisibility;
this._textBoxVisibility = textBoxVisibility;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
为什么不在视图模型中绑定项的可见性呢?
一个例子。
<Textblock Test="{Binding passwordText,ElementName=This}" Visibility="{Binding passwordTextVisibility}"/>
在ViewModel中写入
public Visibility passwordTextVisibility
{
getters and setters here
}
和鼠标事件,在堆栈面板中需要某种路由事件。一个例子:
在堆栈面板内,您将需要鼠标。你需要什么都行。阅读一些关于路由事件的知识
的例子。如果PreviewMouseLeftButtonUp
不工作
<StackPanel Mouse.MouseUp="MouseButtonUpEventHandler"/>
public void MouseButtonUpEventHandler (RoutedEvent e)
{
//logic here to check if it's left mouse if it is then set visibility
}
}