实施“重命名".从ContextMenu [英] Implementing "Rename" from a ContextMenu

查看:40
本文介绍了实施“重命名".从ContextMenu的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从WPF的上下文菜单中实现重命名功能的最佳方法是什么?我想要的是Windows资源管理器之类的功能,您可以在该项目上单击鼠标右键,获得一个上下文菜单,如果选择重命名,则文本变为可编辑的.

What is the best way to implement Rename functionality from a context menu in WPF?, What I want is functionality like Windows Explorer where you right click on an item, get a context menu, and if you select rename, the text becomes editable.

到目前为止,我已经尝试了以下方法,但是我认为必须有更好的方法.该解决方案的几乎任何方面都可以更改:)

So far I've tried the following, but I think there must be a better way. Pretty much any aspect of this solution can be changed :)

<ListBox Grid.Row="0" MinWidth="200" MinHeight="75" ItemsSource="{Binding Path=DataSetsVM.DataSets, Source={StaticResource vmLocator}}" x:Name="dataSets">
<ListBox.ItemTemplate>
    <DataTemplate>
        <StackPanel x:Name="nameRoot">
            <TextBlock x:Name="nameBlock" Text="{Binding Path=Name}" HorizontalAlignment="Stretch" MinWidth="200" Tag="{Binding DataContext, ElementName=dataSets}">
            <TextBlock.ContextMenu> 
                <ContextMenu >
                    <ContextMenu.Resources>
                        <Style TargetType="Image">
                            <Setter Property="Height" Value="24"/>
                            <Setter Property="Width" Value="24"/>
                        </Style>
                    </ContextMenu.Resources>
                    <MenuItem Header="Rename" x:Name="RenameDatasetContext"
                              Command="{Binding PlacementTarget.Tag.CoreCommands.RenameDatasetCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
                              CommandParameter="{Binding PlacementTarget.DataContext, 
                              RelativeSource={RelativeSource FindAncestor, 
                              AncestorType={x:Type ContextMenu}}}">
                        <MenuItem.Icon>
                            <Image Source="{StaticResource RenameLargeIcon}"/>
                        </MenuItem.Icon>
                    </MenuItem>
                </ContextMenu>
            </TextBlock.ContextMenu>
            </TextBlock>
            <TextBox x:Name="nameBox"  Text="{Binding Path=Name}" HorizontalAlignment="Stretch" MinWidth="200" Visibility="Collapsed" />
        </StackPanel>
        <DataTemplate.Triggers>                                            
            <DataTrigger Binding="{Binding Path=IsEditable}" Value="True">
                <Setter TargetName="nameBlock" Property="Visibility" Value="Collapsed"/>
                <Setter TargetName="nameBox" Property="Visibility" Value="Visible"/>
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>
</ListBox.ItemTemplate> 
</ListBox>

名称"的设置者将执行以下操作:

The setter for Name does this:

set
{
    if (IsEditable)
    {
        IsEditable = false;   
        if (_name == value)
        {
            RaisePropertyChanged(NamePropertyName);
            return;
        }
        // Do some back end stuff
        if (back end stuff worked)
        {
            var oldValue = _name;
            _name = value;
            RaisePropertyChanged(NamePropertyName);
        }
        else
        {
            // Do something about the error in the back end
        }
    }   
}

所有命令都将IsEditable设置为true.

All the command does is set IsEditable to true.

这是可行的,除非您实际上没有更改名称,这时没有任何设置使IsEditable变回原来的名称,因为从未调用过Name的设置器,因此您可以在Rename模式下完成一堆项目.

This works unless you don't actually change the name, at which point there's nothing that sets IsEditable back as the setter for Name never gets called, so you can wind up with a bunch of items in Rename mode.

我可以通过触发器在VM上设置属性吗,还是有更好的方法呢?

Can I set a property on a VM through a trigger, or is there a better way to do this?

推荐答案

这会更像MVVM.后面的文件进行快速测试,所有编译/运行.

this would be more MVVM-ish.. I simplified the binding to keep sample short and easy and I just hooked up the ViewModel to the cs. file in the back for quick test, all compiles/runs.

<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>

后面的代码(请注意,视图完全是被动的):

code behind (note, view is completely passive):

public partial class MainWindow : Window
{
    public ViewModel ViewModel { get; set; }

    public MainWindow()
    {
        ViewModel = new ViewModel();
        InitializeComponent();
    }
}

viewModel(具有所有操作逻辑):

viewModel (has all the manipulation logic):

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;
}

模型(完全不了解其他模型,只知道如何设置自己的行为),其属性完全不包含任何逻辑:

Model (completely dumb about other models, only knows how to set it's own behavior) with properties completely clean of any logic:

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;
}

这篇关于实施“重命名".从ContextMenu的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆