none
DataGridでコードから値を設定し、その値を「Esc」キーでキャンセルできるようにしたい RRS feed

  • 質問

  • お世話になります。

    VisualStudio2010 + WPF(C#)にて、DataGridを使って以下のような機能を実現しようとしています。

    (1)DataGridには単価、数量、金額の列があり、それぞれDataTableにバインドしている。

    (2)単価または数量を変更した場合は、単価×数量で金額を計算し、表示する。

    (3)金額を手入力した場合は、(2)の値を上書きできる。

    (4)行の編集途中で「Esc」キーを押した場合は、入力がキャンセルされる。

    実現手段として以下のような方法を検討しましたが、いずれもうまくいきません。

    (a)DataGridのSelectedItemをもとに、DataRowViewを取得し書き換える。

      →【問題a-1】 取得した単価と数量は、行の編集が確定していないので、変更前の値になってしまう。

      →【問題a-2】書き換えた金額は、「Esc」キーを押してもキャンセルされない。

    (b)DataGrid内のTextBlockを取得し、SetCurrentValueで書き換える。

      →【問題b-1】見た目だけ変わるが、中身は変わらない。

    その他、MultiBindingも検討しましたが、単価、数量、金額の関係をうまく表現できず、実現方法が見つかりません。

    行レベルの確定が行われる前の値をどこかで保持しているようなので、そこに値を設定すれば解決すると思うのですが、

    どなたかご存知の方がいれば教えて下さい。よろしくお願いします。

    コードは以下の通りです。

    【XML】

    <Window x:Class="dataGridTest.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:dataGridTest"
            Title="MainWindow" Height="350" Width="525">
        <StackPanel>
            <DataGrid Name="dg" ItemsSource="{Binding}" AutoGenerateColumns="False" CanUserAddRows="False"
                      CellEditEnding="dg_CellEditEnding">
                <DataGrid.Columns>
                    <DataGridTextColumn x:Name="colPrice" Header="単価" Binding="{Binding Path=単価}" />
                    <DataGridTextColumn x:Name="colQty" Header="数量" Binding="{Binding Path=数量}" />
                    <DataGridTextColumn x:Name="colAmount1" Header="金額1" Binding="{Binding Path=金額1}" />
                    <DataGridTextColumn x:Name="colAmount2" Header="金額2" Binding="{Binding Path=金額2}" />
                </DataGrid.Columns>
            </DataGrid>
        </StackPanel>
    </Window>
    

    【C#】

    using System.Data;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace dataGridTest {
        /// <summary>
        /// MainWindow.xaml の相互作用ロジック
        /// </summary>
        public partial class MainWindow : Window {
            public MainWindow() {
                InitializeComponent();
                DataTable dt = new DataTable();
                dt.Columns.Add("単価", typeof(int));
                dt.Columns.Add("数量", typeof(int));
                dt.Columns.Add("金額1", typeof(int));
                dt.Columns.Add("金額2", typeof(int));
                DataRow dr = dt.NewRow();
                dr["単価"] = 10;
                dr["数量"] = 2;
                dr["金額1"] = 20;
                dr["金額2"] = 20;
                dt.Rows.Add(dr);
                dr = dt.NewRow();
                dr["単価"] = 20;
                dr["数量"] = 3;
                dr["金額1"] = 60;
                dr["金額2"] = 60;
                dt.Rows.Add(dr);
                dg.DataContext = dt;
            }
    
            private void dg_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e) {
                if (e.Column == colPrice || e.Column == colQty) {
                    // 方法a
                    DataRowView drv = dg.SelectedItem as DataRowView;
                    if (drv != null) {
                        drv["金額1"] = (int)drv["単価"] * (int)drv["数量"];
                    }
                    // 方法b
                    int price, qty;
                    if (e.Column == colPrice) {
                        TextBox t = (TextBox)colPrice.GetCellContent(e.Row);
                        int.TryParse(t.Text, out price);
                    } else {
                        TextBlock t = (TextBlock)colPrice.GetCellContent(e.Row);
                        int.TryParse(t.Text, out price);
                    }
                    if (e.Column == colQty) {
                        TextBox t = (TextBox)colQty.GetCellContent(e.Row);
                        int.TryParse(t.Text, out qty);
                    } else {
                        TextBlock t = (TextBlock)colQty.GetCellContent(e.Row);
                        int.TryParse(t.Text, out qty);
                    }
                    TextBlock tbAmount2 = (TextBlock)colAmount2.GetCellContent(e.Row);
                    int amount = price * qty;
                    tbAmount2.SetCurrentValue(TextBlock.TextProperty, amount.ToString());
                }
            }
        }
    }
    

    2012年4月16日 6:15

回答

  • DataTableを直接バインドさせない方が良いでしょう。直接バインドしてしまうと、どうしてもDataTableの機能に引きずられてしまい、扱い難くなってしまいます。
    DataGrid <---> ObservableCollection <--> DataTable の形にすると自由度が広がりますので、やりたいことが実現できると思います。自由度が広がるということはその分やらないといけないことが増えるわけですが・・・。
    ちなみに上は、
    View <--> ViewModel <--> Modelという形で考えることもできます。いわゆるMVVMパターンです。MVVMについては、現在では多くの資料が見つかると思いますので調べてみて下さい。
    MVVMパターンを採用しないにしても、上記のObservableCollectionのようなDTO(Data Transfer Object)を用意する方が、結果的に自分でコントロールできる範囲が広がりますので、素直に実装できるはずです。

    (参考)
    Part 2. スマートクライアントにおける単体入力データ検証
    http://blogs.msdn.com/b/nakama/archive/2009/02/26/part-2.aspx


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2012年4月16日 6:41
    モデレータ
  • INotifyPropertyChanged インターフェイスと ObservableCollection クラスを使った DataGrid のサンプルを考えてみました。コードが長いので、三つの返信に分けてコードを提示します。なにかの参考になれば幸いです。

    まず「行」ですが、明細というクラスを定義します。変更通知を受け取れるように INotifyPropertyChanged を実装します。

    using System;
    using System.ComponentModel;
    
    class Detail : INotifyPropertyChanged {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void RaisePropertyChanged(string propertyName) {
            var d = PropertyChanged;
            if (d != null) {
                d(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    
        // 計算
        private void Caliculate() {
            this.Amount1 = this.UnitPrice1 * this.Count;
            this.Amount2 = this.UnitPrice2 * this.Count;
        }
    
        // 単価1
        private Decimal _UnitPrice1;
        public Decimal UnitPrice1 {
            get { return _UnitPrice1; }
            set { 
                _UnitPrice1 = value;
                RaisePropertyChanged("UnitPrice1");
                this.Caliculate();
            }
        }
    
        // 単価2
        private Decimal _UnitPrice2;
        public Decimal UnitPrice2 {
            get { return _UnitPrice2; }
            set { 
                _UnitPrice2 = value;
                RaisePropertyChanged("UnitPrice2");
                this.Caliculate();
            }
        }
    
        // 数量
        private Int32 _Count;
        public Int32 Count {
            get { return _Count; }
            set { 
                _Count = value;
                RaisePropertyChanged("Count");
                this.Caliculate();
            }
        }
    
        // 金額1
        private Decimal _Amount1;
        public Decimal Amount1 {
            get { return _Amount1; }
            set { 
                _Amount1 = value;
                RaisePropertyChanged("Amount1");
            }
        }
    
        // 金額2
        #region Amount2変更通知プロパティ
        private Decimal _Amount2;
    
        public Decimal Amount2 {
            get { return _Amount2; }
            set { 
                _Amount2 = value;
                RaisePropertyChanged("Amount2");
            }
        }
        #endregion
    }


    ひらぽん http://d.hatena.ne.jp/hilapon/

    2012年4月18日 1:53
    モデレータ
  • ObservableCollection の生成は ViewModel に実装しました。ViewModel でコレクションを管理し、DataGrid にバインドします。

    using System.Collections.ObjectModel;
    using System.ComponentModel;
    
    namespace WpfApplication1 {
    
        class ViewModel : INotifyPropertyChanged {
            public event PropertyChangedEventHandler PropertyChanged;
            protected void RaisePropertyChanged(string propertyName) {
                var d = PropertyChanged;
                if (d != null) {
                    d(this, new PropertyChangedEventArgs(propertyName));
                }
            }
    
            public ViewModel() {
                this.Details = new ObservableCollection<Detail>();
                this.Details.Add(new Detail() {
                    UnitPrice1 = 180,
                    UnitPrice2 = 90,
                    Count = 2
                });
                this.Details.Add(new Detail() {
                    UnitPrice1 = 120,
                    UnitPrice2 = 70,
                    Count = 5
                });
                this.Details.Add(new Detail() {
                    UnitPrice1 = 100,
                    UnitPrice2 = 85,
                    Count = 4
                });
            }
    
    
            private ObservableCollection<Detail> _Details;
            public ObservableCollection<Detail> Details {
                get { return _Details; }
                set {
                    _Details = value;
                    RaisePropertyChanged("Details");
                }
            }
        }
    }
    


    ひらぽん http://d.hatena.ne.jp/hilapon/

    2012年4月18日 1:55
    モデレータ
  • 以下は改造した XAML。DataGrid は ViewModel の Details プロパティにバインドし、列は コレクションに格納された Detailオブジェクトの各プロパティとバインドします。これで単価、数量の値を変更すると計算結果がただちに金額に反映されるようになります。DataGrid のイベントを使う必要はありません。

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
            Title="MainWindow" Height="350" Width="525">
        <Window.DataContext>
            <local:ViewModel />
        </Window.DataContext>
        <StackPanel>
            <DataGrid Name="dg" ItemsSource="{Binding Details}" AutoGenerateColumns="False" CanUserAddRows="False">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="単価1" Binding="{Binding Path=UnitPrice1, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Header="単価2" Binding="{Binding Path=UnitPrice2, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Header="数量" Binding="{Binding Path=Count, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Header="金額1" Binding="{Binding Path=Amount1, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Header="金額2" Binding="{Binding Path=Amount2, UpdateSourceTrigger=PropertyChanged}" />
                </DataGrid.Columns>
            </DataGrid>
        </StackPanel>
    </Window>

    今回回答するにあたり MVVM パターンを採用してみました。XAML はビュー、ViewModel はビューモデル、Detail クラスはモデルを表します。


    ひらぽん http://d.hatena.ne.jp/hilapon/



    2012年4月18日 2:00
    モデレータ

すべての返信

  • DataTableを直接バインドさせない方が良いでしょう。直接バインドしてしまうと、どうしてもDataTableの機能に引きずられてしまい、扱い難くなってしまいます。
    DataGrid <---> ObservableCollection <--> DataTable の形にすると自由度が広がりますので、やりたいことが実現できると思います。自由度が広がるということはその分やらないといけないことが増えるわけですが・・・。
    ちなみに上は、
    View <--> ViewModel <--> Modelという形で考えることもできます。いわゆるMVVMパターンです。MVVMについては、現在では多くの資料が見つかると思いますので調べてみて下さい。
    MVVMパターンを採用しないにしても、上記のObservableCollectionのようなDTO(Data Transfer Object)を用意する方が、結果的に自分でコントロールできる範囲が広がりますので、素直に実装できるはずです。

    (参考)
    Part 2. スマートクライアントにおける単体入力データ検証
    http://blogs.msdn.com/b/nakama/archive/2009/02/26/part-2.aspx


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2012年4月16日 6:41
    モデレータ
  • > DataTableを直接バインドさせない方が良いでしょう。直接バインドしてしまうと、どうしてもDataTableの機能に引きずられてしまい、扱い難くなってしまいます。
    > DataGrid <---> ObservableCollection <--> DataTable の形にすると自由度が広がりますので、やりたいことが実現できると思います。自由度が広がるということはその分やらないといけないことが増えるわけですが・・・。
    ・・・・
    > MVVMパターンを採用しないにしても、上記のObservableCollectionのようなDTO(Data Transfer Object)を用意する方が、結果的に自分でコントロールできる範囲が広がりますので、素直に実装できるはずです。

    この意見には私も賛成です。
    私も当初 DataTable とバインドさせてたのですが、最近は ObservableCollection とバインドさせてます。
    各行ごとに INotifyPropertyChanged インターフェイスを実装したオブジェクトがバインドされていれば、DataGrid のイベントに頼らずとも、オブジェクト内で単価・数量の変更通知を受けて計算できます。


    ひらぽん http://d.hatena.ne.jp/hilapon/

    2012年4月17日 1:23
    モデレータ
  • trapemiya様、的確なアドバイスありがとうございます。参考資料も分かりやすく、DataTableを直接バインドすることにより何なく気持ち悪かったのが、すっきりしそうです。

    ひらぽん様もありがとうございます。ちょうどご指摘の点(DataGridのイベントに頼るべきか)についてどうしようかと考えていたので、タイムリーなコメントでした。

    ですが、まだDataGridの機能に引きずられています。引き続き調べていますが、お気づきの点があればアドバイスお願いします。

    DataRowExtクラスは、DataGrid のイベントに頼らずに単価(単価1)の変更を受け取ろうとしているものです。

    DataGridで、行レベルの変更が確定しないとPropertyChangedイベントが発生しません。

    DataGridのイベントに頼って金額(金額2)を計算しているのが、DTOクラスです(ObservableCollectionを使用)。

    セルレベルの確定で金額2を計算できるのですが、DataGridのCellEditEndingイベントを使用し、確定前の値をTextBlockから拾って強引に更新しているので、いまいちすっきりしません。

    【変更後XAML】
    CellEditEnding,BeginningEditイベントの追加と各項目のバインド方法を変更

    <Window x:Class="dataGridTest.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:dataGridTest"
            Title="MainWindow" Height="350" Width="525">
        <StackPanel>
            <DataGrid Name="dg" ItemsSource="{Binding}" AutoGenerateColumns="False" CanUserAddRows="False"
                      CellEditEnding="dg_CellEditEnding" BeginningEdit="dg_BeginningEdit">
                <DataGrid.Columns>
                    <DataGridTextColumn x:Name="colPrice1" Header="単価1" Binding="{Binding Path=単価1}" />
                    <DataGridTextColumn x:Name="colPrice2" Header="単価2" Binding="{Binding Path=[単価2]}" />
                    <DataGridTextColumn x:Name="colQty" Header="数量" Binding="{Binding Path=[数量]}" />
                    <DataGridTextColumn x:Name="colAmount1" Header="金額1" Binding="{Binding Path=[金額1]}" />
                    <DataGridTextColumn x:Name="colAmount2" Header="金額2" Binding="{Binding Path=[金額2]}" />
                </DataGrid.Columns>
            </DataGrid>
        </StackPanel>
    </Window>
    

    【変更後C#】

    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Data;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace dataGridTest {
        /// <summary>
        /// MainWindow.xaml の相互作用ロジック
        /// </summary>
        public partial class MainWindow : Window {
            private DTO _dto; 
    
            public MainWindow() {
                InitializeComponent();
                DataTable dt = new DataTable();
                dt.Columns.Add("単価1", typeof(int));
                dt.Columns.Add("単価2", typeof(int));
                dt.Columns.Add("数量", typeof(int));
                dt.Columns.Add("金額1", typeof(int));
                dt.Columns.Add("金額2", typeof(int));
                DataRow dr = dt.NewRow();
                dr["単価1"] = 10;
                dr["単価2"] = 10;
                dr["数量"] = 2;
                dr["金額1"] = 20;
                dr["金額2"] = 20;
                dt.Rows.Add(dr);
                dr = dt.NewRow();
                dr["単価1"] = 20;
                dr["単価2"] = 20;
                dr["数量"] = 3;
                dr["金額1"] = 60;
                dr["金額2"] = 60;
                dt.Rows.Add(dr);
                _dto = new DTO(dt);
                dg.DataContext = _dto;
            }
    
            private void dg_BeginningEdit(object sender, DataGridBeginningEditEventArgs e) {
                _dto.BeginEdit((DataRowExt)dg.SelectedItem);
            }
    
            private void dg_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e) {
                if (e.EditAction == DataGridEditAction.Commit && e.Column == colPrice2) {
                    int price;
                    TextBox t = (TextBox)colPrice2.GetCellContent(e.Row);
                    int.TryParse(t.Text, out price);
                    _dto.CalcAmount(price);
                }
            }
        }
    
        public class DataRowExt: Dictionary<string,object>, INotifyPropertyChanged  {
            private int _単価1;
    
            public DataRowExt(DataRow dr) {
                foreach (DataColumn dc in dr.Table.Columns) {
                    this.Add(dc.ColumnName, dr[dc]); 
                }
                this.単価1 = (int)dr["単価1"];
            }
    
            public int 単価1 {
                get { return _単価1; }
                set {
                    if (_単価1 != value) {
                        _単価1 = value;
                        RaisePropertyChanged("単価1");
                    }
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void RaisePropertyChanged(string propertyName) {
                var d = PropertyChanged;
                if (d != null) {
                    d(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    
        public class DTO : ObservableCollection<DataRowExt> {
            DataTable _dt;
            DataRowExt _drxCurrent;
    
            public DTO(DataTable dt)
                : base() {
                _dt = dt.Copy();
                foreach (DataRow dr in _dt.Rows) {
                    DataRowExt drx = new DataRowExt(dr);
                    drx.PropertyChanged += new PropertyChangedEventHandler(this.drx_PropertyChanged);
                    this.Add(drx);
                }
            }
    
            public void BeginEdit(DataRowExt dr) {
                _drxCurrent = dr;
            }
    
            private void drx_PropertyChanged(object sender, PropertyChangedEventArgs e) {
                _drxCurrent["金額1"] = _drxCurrent.単価1 * (int)_drxCurrent["数量"];
                this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }
    
            public void CalcAmount(int price) {
                _drxCurrent["金額2"] = price * (int)_drxCurrent["数量"];
                _drxCurrent["単価2"] = price;
                this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }
        }
    }
    
    2012年4月17日 9:25
  • INotifyPropertyChanged インターフェイスと ObservableCollection クラスを使った DataGrid のサンプルを考えてみました。コードが長いので、三つの返信に分けてコードを提示します。なにかの参考になれば幸いです。

    まず「行」ですが、明細というクラスを定義します。変更通知を受け取れるように INotifyPropertyChanged を実装します。

    using System;
    using System.ComponentModel;
    
    class Detail : INotifyPropertyChanged {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void RaisePropertyChanged(string propertyName) {
            var d = PropertyChanged;
            if (d != null) {
                d(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    
        // 計算
        private void Caliculate() {
            this.Amount1 = this.UnitPrice1 * this.Count;
            this.Amount2 = this.UnitPrice2 * this.Count;
        }
    
        // 単価1
        private Decimal _UnitPrice1;
        public Decimal UnitPrice1 {
            get { return _UnitPrice1; }
            set { 
                _UnitPrice1 = value;
                RaisePropertyChanged("UnitPrice1");
                this.Caliculate();
            }
        }
    
        // 単価2
        private Decimal _UnitPrice2;
        public Decimal UnitPrice2 {
            get { return _UnitPrice2; }
            set { 
                _UnitPrice2 = value;
                RaisePropertyChanged("UnitPrice2");
                this.Caliculate();
            }
        }
    
        // 数量
        private Int32 _Count;
        public Int32 Count {
            get { return _Count; }
            set { 
                _Count = value;
                RaisePropertyChanged("Count");
                this.Caliculate();
            }
        }
    
        // 金額1
        private Decimal _Amount1;
        public Decimal Amount1 {
            get { return _Amount1; }
            set { 
                _Amount1 = value;
                RaisePropertyChanged("Amount1");
            }
        }
    
        // 金額2
        #region Amount2変更通知プロパティ
        private Decimal _Amount2;
    
        public Decimal Amount2 {
            get { return _Amount2; }
            set { 
                _Amount2 = value;
                RaisePropertyChanged("Amount2");
            }
        }
        #endregion
    }


    ひらぽん http://d.hatena.ne.jp/hilapon/

    2012年4月18日 1:53
    モデレータ
  • ObservableCollection の生成は ViewModel に実装しました。ViewModel でコレクションを管理し、DataGrid にバインドします。

    using System.Collections.ObjectModel;
    using System.ComponentModel;
    
    namespace WpfApplication1 {
    
        class ViewModel : INotifyPropertyChanged {
            public event PropertyChangedEventHandler PropertyChanged;
            protected void RaisePropertyChanged(string propertyName) {
                var d = PropertyChanged;
                if (d != null) {
                    d(this, new PropertyChangedEventArgs(propertyName));
                }
            }
    
            public ViewModel() {
                this.Details = new ObservableCollection<Detail>();
                this.Details.Add(new Detail() {
                    UnitPrice1 = 180,
                    UnitPrice2 = 90,
                    Count = 2
                });
                this.Details.Add(new Detail() {
                    UnitPrice1 = 120,
                    UnitPrice2 = 70,
                    Count = 5
                });
                this.Details.Add(new Detail() {
                    UnitPrice1 = 100,
                    UnitPrice2 = 85,
                    Count = 4
                });
            }
    
    
            private ObservableCollection<Detail> _Details;
            public ObservableCollection<Detail> Details {
                get { return _Details; }
                set {
                    _Details = value;
                    RaisePropertyChanged("Details");
                }
            }
        }
    }
    


    ひらぽん http://d.hatena.ne.jp/hilapon/

    2012年4月18日 1:55
    モデレータ
  • 以下は改造した XAML。DataGrid は ViewModel の Details プロパティにバインドし、列は コレクションに格納された Detailオブジェクトの各プロパティとバインドします。これで単価、数量の値を変更すると計算結果がただちに金額に反映されるようになります。DataGrid のイベントを使う必要はありません。

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
            Title="MainWindow" Height="350" Width="525">
        <Window.DataContext>
            <local:ViewModel />
        </Window.DataContext>
        <StackPanel>
            <DataGrid Name="dg" ItemsSource="{Binding Details}" AutoGenerateColumns="False" CanUserAddRows="False">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="単価1" Binding="{Binding Path=UnitPrice1, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Header="単価2" Binding="{Binding Path=UnitPrice2, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Header="数量" Binding="{Binding Path=Count, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Header="金額1" Binding="{Binding Path=Amount1, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Header="金額2" Binding="{Binding Path=Amount2, UpdateSourceTrigger=PropertyChanged}" />
                </DataGrid.Columns>
            </DataGrid>
        </StackPanel>
    </Window>

    今回回答するにあたり MVVM パターンを採用してみました。XAML はビュー、ViewModel はビューモデル、Detail クラスはモデルを表します。


    ひらぽん http://d.hatena.ne.jp/hilapon/



    2012年4月18日 2:00
    モデレータ
  • ひらぽん様ありがとうございます。非常に美しくなりますね。理解できました。

    UpdateSourceTriggerを指定して、制御をViewModelクラスに任せてしまうことで、操作性も自然で、拡張が自由になるのですね。

    DataGridの機能に囚われていたことが良く分かりました。

    ありがとうございます。

    2012年4月18日 4:16
  • 初めまして、初心者です

    上記回答にて自動計算が出来るグリッドが作成できますが、外部のclass MainWindowからDetailsのセルの数値を変更するにはどうすれば良いのでしょうか

    ヒント、文献などご紹介頂きたくよろしくお願いします

    2013年6月22日 9:49
  • wpfの考え方では、MainWindowからセルの値を変更せずに、ViewModelクラスから値を変更します。

    ViewModelクラスのDetailsプロパティをMainWindowにバインド(XAMLの ItemsSource="{Binding Details}" )しているので、Detailsに格納されているDetailクラスの値を変更すれば、自動的に画面に反映されます。

    2013年6月22日 10:03
  • newon1さま

    モデレーターとしてお願いがあります。申し訳ありませんが、新しい質問は新しいスレッドとして作成していただけませんでしょうか? このフォーラムは誰でも閲覧することができます。後からこのフォーラムを見に来た人が探しやすいように情報が掲載されていると、その人にとって時間の節約になります。
    新しいスレッドを作成するには、画面左上にある、青地に白色の文字で書かれた「質問する」というところをクリックしてください。
    最初は誰でも不慣れなものです。質問上手はプログラムの上達も早いと思いますので、質問上手の腕も磨かれると良いと思いますよ。



    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2013年6月22日 15:03
    モデレータ
  • モデレーター様

    不適切な行為にご指摘頂きありがとうございます

    先ほどの投稿は撤回させて頂きました

    新たな質問として上掲させて頂きましたが、右も左もわからない状態で質問自体がおかしい可能性があります

    今後もご指導頂けますと幸いです

    2013年6月22日 16:31