C# 实施";更名为;从上下文菜单
在WPF中,从上下文菜单实现重命名功能的最佳方法是什么?我想要的是类似Windows资源管理器的功能,在该功能中,右键单击某个项目,获得上下文菜单,如果选择“重命名”,文本将变为可编辑 到目前为止,我已经尝试了以下方法,但我认为一定有更好的方法。此解决方案的几乎任何方面都可以更改:) 命令所做的一切都设置为“可编辑” 除非您实际上没有更改名称,否则这是可行的,在这一点上,没有任何东西可以将IsEditable设置回,因为名称的setter从未被调用,因此您可以在重命名模式下处理大量项C# 实施";更名为;从上下文菜单,c#,.net,wpf,mvvm,C#,.net,Wpf,Mvvm,在WPF中,从上下文菜单实现重命名功能的最佳方法是什么?我想要的是类似Windows资源管理器的功能,在该功能中,右键单击某个项目,获得上下文菜单,如果选择“重命名”,文本将变为可编辑 到目前为止,我已经尝试了以下方法,但我认为一定有更好的方法。此解决方案的几乎任何方面都可以更改:) 命令所做的一切都设置为“可编辑” 除非您实际上没有更改名称,否则这是可行的,在这一点上,没有任何东西可以将IsEditable设置回,因为名称的setter从未被调用,因此您可以在重命名模式下处理大量项 我可以通过
我可以通过触发器在VM上设置属性吗,或者有更好的方法吗?这很奇怪,但考虑到您的代码(其编写方式),您的情况很糟糕,因此最简单/最快的解决方案是在开始编辑新的列表框项目之前重置所有列表框项目: 在添加到nameBlock mousedown事件的XAML中:
<TextBlock x:Name="nameBlock" MouseDown="nameBlock_MouseDown"...
还从setter中删除了IsEditable检查
set
{
//if (IsEditable)
{
//IsEditable = false;
if (_name == value)
{
RaisePropertyChanged("Name");
return;
}
// Do some back end stuff
if (back //end stuff //worked)
{
var oldValue = _name;
_name = value;
RaisePropertyChanged("Name");
}
}
这很奇怪,但考虑到您的代码(其编写方式),您正处于一种令人不安的状态,因此最简单/最快速的解决方案是在开始编辑新的列表框项目之前重置所有列表框项目: 在添加到nameBlock mousedown事件的XAML中:
<TextBlock x:Name="nameBlock" MouseDown="nameBlock_MouseDown"...
还从setter中删除了IsEditable检查
set
{
//if (IsEditable)
{
//IsEditable = false;
if (_name == value)
{
RaisePropertyChanged("Name");
return;
}
// Do some back end stuff
if (back //end stuff //worked)
{
var oldValue = _name;
_name = value;
RaisePropertyChanged("Name");
}
}
两件事
首先,如果您试图使它的行为类似于Windows资源管理器,那么您应该向Esc添加一个设置IsEditable=false的键绑定
其次,您需要在文本框中为LostFocus添加一个触发器,将IsEditable设置为false。
首先,如果您试图使它的行为类似于Windows资源管理器,那么您应该向Esc添加一个设置IsEditable=false的键绑定
其次,您需要在文本框中为LostFocus添加一个触发器,该触发器将IsEditable设置为false。这将更符合MVVM标准。。我简化了绑定以保持示例的简洁性,并将ViewModel连接到cs。文件在后面,用于快速测试,所有编译/运行
<Window x:Class="Sample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="350" Width="525"
x:Name="wnd">
<ListBox ItemsSource="{Binding ViewModel.Items, ElementName=wnd}"
SelectedItem="{Binding ViewModel.SelectedItem, ElementName=wnd}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock x:Name="nameBlock" Text="{Binding Name}" Margin="4">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Rename"
Command="{Binding EditItemCommand}">
</MenuItem>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
<TextBox x:Name="nameBox" Text="{Binding Name}" Visibility="Collapsed" Margin="2,0"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsEditable}" Value="True">
<Setter TargetName="nameBlock" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="nameBox" Property="Visibility" Value="Visible"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
viewModel(具有所有操作逻辑):
这会更像MVVM。。我简化了绑定以保持示例的简洁性,并将ViewModel连接到cs。文件在后面,用于快速测试,所有编译/运行
<Window x:Class="Sample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="350" Width="525"
x:Name="wnd">
<ListBox ItemsSource="{Binding ViewModel.Items, ElementName=wnd}"
SelectedItem="{Binding ViewModel.SelectedItem, ElementName=wnd}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock x:Name="nameBlock" Text="{Binding Name}" Margin="4">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Rename"
Command="{Binding EditItemCommand}">
</MenuItem>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
<TextBox x:Name="nameBox" Text="{Binding Name}" Visibility="Collapsed" Margin="2,0"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsEditable}" Value="True">
<Setter TargetName="nameBlock" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="nameBox" Property="Visibility" Value="Visible"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
viewModel(具有所有操作逻辑):
IsEditable实现INotifyPropertyChanged了吗?是的-正如我所说,它一直工作到您开始重命名并且没有实际更改名称:)IsEditable实现INotifyPropertyChanged了吗?是的-正如我所说,它一直工作到您开始重命名并且没有实际更改名称:)我假设“数据集”是您的列表框的名称,而“SomeClass”是将listbox项绑定到的类型(具有名称和IsEditable属性的类型)。我认为这种情况并不奇怪,尽管我可能已经想出了一些奇怪的代码试图解决它。我愿意接受一些建议,包括以一种非常不同的方式(但仍然是MVVMish)来做这件事:)对不起,我不是有意用“funky”来侮辱你。为了澄清,我看到的是funky在名称的setter中使用了IsEditable状态。我想如果你把IsEditabe支票从那里删除,事情就会朝着解决问题的方向发展。此外,这是一个useles检查,因为您切换textblock和textbox已经使得在ISEditable为false时无法设置名称。这是一个很好的谜题,我将继续玩:)添加了一个更具MVVM风格的方法。Good luckI假设“数据集”是listbox的名称,“SomeClass”是将listbox项绑定到的类型(具有名称和IsEditable属性的类型)。我不认为这种情况很奇怪,尽管我可能已经想出了一些奇怪的代码试图解决它。我愿意接受一些建议,包括以一种非常不同的方式(但仍然是MVVMish)来做这件事:)对不起,我不是有意用“funky”来侮辱你。为了澄清,我看到的是funky在名称的setter中使用了IsEditable状态。我想如果你把IsEditabe支票从那里删除,事情就会朝着解决问题的方向发展。此外,这是一个useles检查,因为您切换textblock和textbox已经使得在ISEditable为false时无法设置名称。这是一个很好的谜题,我将继续玩:)添加了一个更具MVVM风格的方法。幸运的是,使用此解决方案,如何恢复文本框和文本块以前的可视性?@user1722791:我在文本框
中添加了一个InteractionTrigger,如何恢复文本框和文本块以前的可见性?@user1722791:我在文本框中添加了一个InteractionTrigger
public partial class MainWindow : Window
{
public ViewModel ViewModel { get; set; }
public MainWindow()
{
ViewModel = new ViewModel();
InitializeComponent();
}
}
public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<SomeClass> _items;
private SomeClass _selectedItem;
public ViewModel()
{
SelectedItem = Items.First();
}
public ObservableCollection<SomeClass> Items
{
get
{
if (_items == null)
{
_items = new ObservableCollection<SomeClass>();
for (int i = 0; i < 10; i++) _items.Add(new SomeClass(string.Format("name {0}", i)));
}
return _items;
}
}
public SomeClass SelectedItem
{
get { return _selectedItem; }
set
{
if (_selectedItem == value)
return;
_selectedItem = value;
foreach (var item in Items) item.IsEditable = false;
RaisePropertyChanged("SelectedItem");
}
}
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class SomeClass : INotifyPropertyChanged
{
private string _name;
private bool _isEditable;
private DelegateCommand _editItemCmd;
public SomeClass(string name) { _name = name;}
public DelegateCommand EditItemCommand
{
get
{
return _editItemCmd ?? (_editItemCmd = new DelegateCommand(() => { IsEditable = true; }));
}
}
public string Name
{
get { return _name; }
set
{
if (_name == value)
return;
_name = value;
RaisePropertyChanged("Name");
}
}
public bool IsEditable
{
get { return _isEditable; }
set
{
if(_isEditable == value)
return;
_isEditable = value;
RaisePropertyChanged("IsEditable");
}
}
private void RaisePropertyChanged(string propertyName)
{
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}