1

私は WPF を持ってGridおり、ユーザーの入力に応じて行を上下に移動したいと考えています。これは私がこれまでに試したことです (ユーザーが要素を上に移動することを決定した場合の例):

RowDefinition currentRow = fieldsGrid.RowDefinitions[currentIndex];
fieldsGrid.RowDefinitions.Remove(currentRow);
fieldsGrid.RowDefinitions.Insert(currentIndex - 1, currentRow);

私は何か間違ったことをしていますか?このアプローチを使用してもUIは同じままです。

4

3 に答える 3

3

以下は、ItemsControl を使用して必要なことを行う簡単な例です。

ビューモデル

public class ListBoxViewModel
{
    private static readonly  List<string> sortList = new List<string>() { "Unsorted", "Sorted" };
    public List<string> SortList { get { return sortList; } }

    public ObservableCollection<ItemDetail> ItemDetails { get; set; }

    #region Up Command
    ICommand upCommand;
    public ICommand UpCommand
    {
        get
        {
            if (upCommand == null)
            {
                upCommand = new RelayCommand(UpExecute);
            }
            return upCommand;
        }
    }

    private void UpExecute(object param)
    {
        var id = param as ItemDetail;

        if (id != null)
        {
            var curIndex = ItemDetails.IndexOf(id);
            if (curIndex > 0)
                ItemDetails.Move(curIndex, curIndex - 1);
        }
    }
    #endregion Up Command

    #region Down Command
    ICommand downCommand;
    public ICommand DownCommand
    {
        get
        {
            if (downCommand == null)
            {
                downCommand = new RelayCommand(DownExecute);
            }
            return downCommand;
        }
    }

    private void DownExecute(object param)
    {
        var id = param as ItemDetail;
        if (id != null)
        {
            var curIndex = ItemDetails.IndexOf(id);
            if (curIndex < ItemDetails.Count-1)
                ItemDetails.Move(curIndex, curIndex + 1);
        }
    }
    #endregion Down Command

    public ListBoxViewModel()
    {
        ItemDetails = new ObservableCollection<ItemDetail>()
        {
            new ItemDetail() { IsSelected = false, ItemName = "Customer Id", SortOrder = "Unsorted" },
            new ItemDetail() { IsSelected = true, ItemName = "Customer Name", SortOrder = "Sorted" },
            new ItemDetail() { IsSelected = false, ItemName = "Customer Age", SortOrder = "Unsorted" }
        };
    }
}

ItemDetail クラス (簡単にするために私が作成しました)

public class ItemDetail
{
    public bool IsSelected { get; set; }
    public string ItemName { get; set; }
    public string SortOrder { get; set; }
}

XAML

<UserControl.Resources>     
    <DataTemplate DataType="{x:Type vm:ItemDetail}">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition SharedSizeGroup="CheckBoxGroup" />
                <ColumnDefinition SharedSizeGroup="ItemNameGroup" />
                <ColumnDefinition SharedSizeGroup="SortGroup" />
                <ColumnDefinition Width="20" />
                <ColumnDefinition SharedSizeGroup="UpArrowGroup" />
                <ColumnDefinition SharedSizeGroup="DownArrowGroup" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <CheckBox Grid.Column="0" IsChecked="{Binding IsSelected}" VerticalAlignment="Center" />
            <Label Grid.Column="1" Content="{Binding ItemName}" />
            <ComboBox Grid.Column="2" ItemsSource="{Binding DataContext.SortList, RelativeSource={RelativeSource AncestorType={x:Type views:ListBoxExample}}}" SelectedItem="{Binding SortOrder}" />
            <Button Grid.Column="4" Command="{Binding DataContext.UpCommand, RelativeSource={RelativeSource AncestorType={x:Type views:ListBoxExample}}}" CommandParameter="{Binding}">
                <Image Source="..\images\up.png" Height="10" />
            </Button>
            <Button Grid.Column="5" Command="{Binding DataContext.DownCommand, RelativeSource={RelativeSource AncestorType={x:Type views:ListBoxExample}}}" CommandParameter="{Binding}">
                <Image Source="..\images\down.png" Height="10" />
            </Button>
        </Grid>
    </DataTemplate>
</UserControl.Resources>

<Grid Grid.IsSharedSizeScope="True">
    <ItemsControl ItemsSource="{Binding ItemDetails}" />
</Grid>

そして最後に結果:

ここに画像の説明を入力

そして、最初の項目で下矢印を押した後:

ここに画像の説明を入力

お役に立てれば。

于 2013-02-26T17:49:08.797 に答える
3

これは、スクリーンショットがどのように見えるかに対する WPF アプローチです。

<Window x:Class="WpfApplication4.Window9"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window9" Height="300" Width="500">
    <ItemsControl ItemsSource="{Binding Columns}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <DataTemplate.Resources>
                    <BooleanToVisibilityConverter x:Key="BoolToVisConverter"/>
                </DataTemplate.Resources>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="20"/>
                        <ColumnDefinition Width="50"/>
                        <ColumnDefinition/>
                        <ColumnDefinition Width="100"/>
                        <ColumnDefinition Width="25"/>
                        <ColumnDefinition Width="25"/>
                    </Grid.ColumnDefinitions>

                    <!-- This is your Key image, I used a rectangle instead, you can change it -->
                    <Rectangle Fill="Yellow" Visibility="{Binding IsPrimaryKey, Converter={StaticResource BoolToVisConverter}}"  Margin="2"/>

                    <CheckBox IsChecked="{Binding IsSelected}" Grid.Column="1"/>

                    <TextBlock Text="{Binding Name}" Grid.Column="2"/>

                    <ComboBox ItemsSource="{Binding SortOrders}" SelectedItem="{Binding SortOrder}" Grid.Column="3" Margin="2"/>

                    <Button Content="Up" Grid.Column="4" Margin="2"
                            Command="{Binding DataContext.MoveUpCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=ItemsControl}}"
                            CommandParameter="{Binding}"/>

                    <Button Content="Down" Grid.Column="5" Margin="2"
                            Command="{Binding DataContext.MoveDownCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=ItemsControl}}"
                            CommandParameter="{Binding}"/>

                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Window>

コードビハインド:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using InduraClientCommon.MVVM;
using System.Collections.ObjectModel;

namespace WpfApplication4
{
    public partial class Window9 : Window
    {
        public Window9()
        {
            InitializeComponent();

            var vm = new ColumnListViewModel();
            vm.Columns.Add(new ColumnViewModel() { IsPrimaryKey = true, Name = "Customer ID", SortOrder = SortOrder.Ascending });
            vm.Columns.Add(new ColumnViewModel() {Name = "Customer Name", SortOrder = SortOrder.Descending});
            vm.Columns.Add(new ColumnViewModel() {Name = "Customer Age", SortOrder = SortOrder.Unsorted});

            DataContext = vm;
        }
    }
}

ビューモデル:

 public class ColumnListViewModel: ViewModelBase
    {
        private ObservableCollection<ColumnViewModel> _columns;
        public ObservableCollection<ColumnViewModel> Columns
        {
            get { return _columns ?? (_columns = new ObservableCollection<ColumnViewModel>()); }
        }

        private DelegateCommand<ColumnViewModel> _moveUpCommand;
        public DelegateCommand<ColumnViewModel> MoveUpCommand
        {
            get { return _moveUpCommand ?? (_moveUpCommand = new DelegateCommand<ColumnViewModel>(MoveUp, x => Columns.IndexOf(x) > 0)); }
        }

        private DelegateCommand<ColumnViewModel> _moveDownCommand;
        public DelegateCommand<ColumnViewModel> MoveDownCommand
        {
            get { return _moveDownCommand ?? (_moveDownCommand = new DelegateCommand<ColumnViewModel>(MoveDown, x => Columns.IndexOf(x) < Columns.Count)); }
        }

        private void MoveUp(ColumnViewModel item)
        {
            var index = Columns.IndexOf(item);
            Columns.Move(index, index - 1);
            MoveUpCommand.RaiseCanExecuteChanged();
            MoveDownCommand.RaiseCanExecuteChanged();
        }

        private void MoveDown(ColumnViewModel item)
        {
            var index = Columns.IndexOf(item);
            Columns.Move(index, index + 1);
            MoveUpCommand.RaiseCanExecuteChanged();
            MoveDownCommand.RaiseCanExecuteChanged();
        }
    }

    public class ColumnViewModel: ViewModelBase
    {
        private bool _isPrimaryKey;
        public bool IsPrimaryKey
        {
            get { return _isPrimaryKey; }
            set
            {
                _isPrimaryKey = value;
                NotifyPropertyChange(() => IsPrimaryKey);
            }
        }

        private bool _isSelected;
        public bool IsSelected
        {
            get { return _isSelected; }
            set
            {
                _isSelected = value;
                NotifyPropertyChange(() => IsSelected);
            }
        }

        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                NotifyPropertyChange(() => Name);
            }
        }

        private List<SortOrder> _sortOrders;
        public List<SortOrder> SortOrders
        {
            get { return _sortOrders ?? (_sortOrders = Enum.GetValues(typeof(SortOrder)).OfType<SortOrder>().ToList()); }
        }

        private SortOrder _sortOrder;
        public SortOrder SortOrder
        {
            get { return _sortOrder; }
            set
            {
                _sortOrder = value;
                NotifyPropertyChange(() => SortOrder);
            }
        }
    }

    public enum SortOrder {Unsorted, Ascending, Descending}
}

これは私の画面では次のようになります。

ここに画像の説明を入力

上記の例でわかるように、コードで UI 要素を操作したり作成したりすることは決してありません。実際には必要ないからです。画面に表示される情報を操作する必要があるときはいつでも、 ではなく を操作しViewModelますView。これは、WPF が可能にする UI とアプリケーション ロジック間の懸念の明確な分離であり、他のフレームワークにはまったく存在しません。WPF であらゆる種類の N 要素 UI を実行する場合は、このアプローチが事実上のデフォルトであると考えてください。

編集:

このアプローチとclassic1 つのアプローチの利点:

  • 画面からデータを表示/取得するためにコード内で複雑な WPF クラス (IE UI 要素) を操作する必要はありません (単純な単純なプロパティと INotifyPropertyChanged のみ)。
  • スケーリングの向上 (ViewModel プロパティを尊重する限り、UI は何でもかまいません。ComboBox を回転する 3D ピンクの象に変更し、各足で並べ替え順序を指定できます。
  • 神がどこにあるかを知っている要素を見つけるためにビジュアル ツリーをナビゲートする必要はありません。
  • 何もする必要はありませんforeachSelectデータを(取得したデータソースから) ViewModelリストに変換するだけの単純なものです。

結論: WPF アプローチを使用する場合、WPF は現在存在する他の何よりもはるかに単純で優れています。

于 2013-02-26T17:58:23.360 に答える
1

RowDefinitionの順序を変更していますが、これは必要なものではありません。Grid.Row 添付プロパティによって決定される行への要素の割り当てを変更したい

各行に属するすべてのコントロールをコンテナー (行ごとに 1 つ) に配置し、Grid.SetRow を使用してコンテナーを変更します。コントロールのグリッド行を wpf のコード ビハインドから変更する方法を参照してください。

于 2013-02-26T16:34:10.617 に答える