2012-04-11 11 views
3

私はlinq、wpf、およびC#を初めて使用しています。私は、機能コンポーネントへの道を研究することに成功しました。私はデータバインディングを成功裏に攻撃しましたが、私はパフォーマンスに苦しんでいます。私は静的な外部XMLファイル(つまりデータベース)を読み込み、wpfデータグリッドを使用してそれをユーザーに表示したいと考えています。情報の追加ビットは、データベースからのデータの量をグリッドに表示するために、ユーザーが制御するwpfコンボボックスを使用していることです。私はこのタスクを達成するためにlinqを使用したいと思いますが、正しく実行するようには思えません。Linqを使用してObservableCollectionにxmlを解析します。 wpfを使用してデータグリッドにデータをバインドする#

C#ファイル:

namespace ReadPipeXMLDB 

{
公共部分クラスReadDB:ウィンドウ、 {プライベートXDocumentのXMLDOC = NULLをINotifyPropertyChangedの。
const string ALL = "すべて";

// Constructor 
    public ReadDB() 
    { 
     InitializeComponent(); 

     // Load xml    
     xmlDoc = XDocument.Load("DataBase.xml"); 
     this.DataContext = this;      
    } 

    private ObservableCollection<CPipeData> _col; 
    public ObservableCollection<CPipeData> Col 
    { 
     get { return _col; } 
     set 
     { 
      if (_col == value) 
       return; 

      _col = value; 
      OnPropertyChanged(() => Col); 
     } 
    } 

    private ObservableCollection<CMfgData> _mfgCollection; 
    public ObservableCollection<CMfgData> MfgCollection 
    { 
     get { return _mfgCollection; } 
     set 
     { 
      if (_mfgCollection == value) 
       return; 

      _mfgCollection = value; 
      OnPropertyChanged(() => MfgCollection); 
     }   
    } 

    private ObservableCollection<string> _mfgNames; 
    public ObservableCollection<string> MfgNames 
    { 
     get { return this._mfgNames; } 
     set 
     { 
      if (this._mfgNames == value) 
       return; 

      this._mfgNames = value; 
      OnPropertyChanged(() => MfgNames); 
     } 
    } 



    #region Notify Event Declaration and Definition 

    public event PropertyChangedEventHandler PropertyChanged; 

    public virtual void OnPropertyChanged<T>(Expression<Func<T>> property) 
    { 
     PropertyChangedEventHandler eventHandler = this.PropertyChanged; 
     if (eventHandler != null) 
     { 
      var memberExpression = property.Body as MemberExpression; 
      eventHandler(this, new PropertyChangedEventArgs(memberExpression.Member.Name)); 
     } 
    } 

    #endregion 


    public class CMfgData : ReadDB 
    { 
     private string _mfgName; 
     //private ObservableCollection<CPipeData> _pipeDataCollection; 



     /*public CMfgData(string mfgName, CPipeData pipeData) 
     {    
      _mfgName = mfgName; 
      _pipeData = pipeData; 
     }*/ 

     #region CMfgData Property Definitions 

     public string MfgName 
     { 
      get { return _mfgName; } 
      set 
      { 
       if (_mfgName == value) 
        return; 

       _mfgName = value; 
       OnPropertyChanged(() => MfgName); 
      } 
     } 

     /* public ObservableCollection<CPipeData> PipeDataCollection 
     { 
      get { return _pipeDataCollection; } 
      set 
      { 
       if (_pipeDataCollection == value) 
        return; 

       _pipeDataCollection = value; 
       OnPropertyChanged(() => PipeDataCollection); 
      } 
     }*/ 

     #endregion 
    } 

    public class CPipeData : ReadDB 
    { 
     // PipeData Property Declarations 
     private string _nominal; 
     private string _sched; 
     private string _id; 
     private string _od; 
     private string _wt; 

     public CPipeData() 
     { 
      _nominal = ""; 
      _sched = ""; 
      _id = ""; 
      _od = ""; 
      _wt = ""; 
     } 

     // Constructor 
     public CPipeData(string nominal, string sched, string id, string od, string wt) 
     { 
      _nominal = nominal; 
      _sched = sched; 
      _id = id; 
      _od = od; 
      _wt = wt; 
     } 

     #region CPipeData Property Definitions 

     public string Nominal 
     { 
      get { return _nominal; } 
      set 
      { 
       if (_nominal == value) 
        return; 

       _nominal = value; 
       OnPropertyChanged(() => Nominal); 
      } 
     } 

     public string Sched 
     { 
      get { return _sched; } 
      set 
      { 
       if (_sched == value) 
        return; 

       _sched = value; 
       OnPropertyChanged(() => Sched); 
      } 
     } 

     public string ID 
     { 
      get { return _id; } 
      set 
      { 
       if (_id == value) 
        return; 

       _id = value; 
       OnPropertyChanged(() => ID); 
      } 
     } 

     public string OD 
     { 
      get { return _od; } 
      set 
      { 
       if (_od == value) 
        return; 

       _od = value; 
       OnPropertyChanged(() => OD); 
      } 
     } 

     public string WT 
     { 
      get { return _wt; } 
      set 
      { 
       if (_wt == value) 
        return; 

       _wt = value; 
       OnPropertyChanged(() => WT); 
      } 
     } 

     #endregion 
    } 



    private void mfgrComboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     // Update database grid 
     if (mfgrComboBox1.SelectedValue is string) 
     {     
      PopulateGrid(mfgrComboBox1.SelectedValue as string); 
     } 
    } 


    private void Window_Loaded(object sender, RoutedEventArgs e) 
    {      
     /*MfgCollection = new ObservableCollection<CMfgData>(        
      from mfg in xmlDoc.Root.Elements("Mfg")        
      //where mfg.Attribute("name").Value == comboValue 
      select new CMfgData 
      { 
       MfgName = mfg.Attribute("name").Value, 
       PipeDataCollection = 
        new ObservableCollection<CPipeData> 
        (from pipe in mfg.Elements("pipe")         
        select new CPipeData 
        {  
         Nominal = pipe.Element("Nominal").Value, 
         Sched = pipe.Element("Schedule").Value, 
         ID = pipe.Element("ID").Value, 
         OD = pipe.Element("OD").Value, 
         WT = pipe.Element("Wall_Thickness").Value 
        }) 

      });*/ 
    } 


    private void mfgrComboBox1_Loaded(object sender, RoutedEventArgs e) 
    { 
     // Make sure xml document has been loaded    
     if (xmlDoc != null) 
     {        
      ObservableCollection<string> tempCollection = new ObservableCollection<string>(    
       from n in xmlDoc.Root.Elements("Mfg").Attributes("name") 
       select n.Value);     

      // Add the additional "All" filter 
      tempCollection.Insert(0, ALL); 

      // Assign list to member property. This is done last so the property event gets fired only once     
      MfgNames = tempCollection;     

      PopulateGrid(ALL);     
     } 
    } 


    private void PopulateGrid(string comboValue) 
    { 
     if (mfgrComboBox1.Items.IndexOf(comboValue) > -1) 
     {      
      Col = new ObservableCollection<CPipeData>(
       from mfg in xmlDoc.Root.Elements("Mfg") 
       where mfg.Attribute("name").Value == comboValue 
       from pipe in mfg.Elements("pipe") 
       select new CPipeData 
       { 
        Nominal = pipe.Element("Nominal").Value, 
        Sched = pipe.Element("Schedule").Value, 
        ID = pipe.Element("ID").Value, 
        OD = pipe.Element("OD").Value, 
        WT = pipe.Element("Wall_Thickness").Value 
       }); 
     } 
    } 
} 

}

XAML:

<Window x:Class="ReadPipeXMLDB.ReadDB" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"   
    Title="Standard Pipe Sizes" Height="849" Width="949" Loaded="Window_Loaded"> 

<Grid>   

    <!-- Manufactuer filter combobox --> 
    <ComboBox Name="mfgrComboBox1" 
       ItemsSource="{Binding Path=MfgNames}" 
       SelectedIndex="0" 
       Height="23" Width="286" 
       HorizontalAlignment="Left" VerticalAlignment="Top"     
       Margin="20,20,0,0" SelectionChanged="mfgrComboBox1_SelectionChanged" Loaded="mfgrComboBox1_Loaded" />  

    <!-- Units combobox --> 
    <ComboBox Height="23" HorizontalAlignment="Left" Margin="320,20,0,0" Name="dimensionsComboBox2" VerticalAlignment="Top" Width="87" />    

    <!-- Pipe database display grid --> 
    <DataGrid Name="dataGrid1" IsReadOnly="True" AutoGenerateColumns="False" Margin="20,60,20,20" ItemsSource="{Binding Col}"> 
     <DataGrid.Columns> 
      <DataGridTextColumn Header="Nominal" Binding="{Binding Path=Nominal}"/> 
      <DataGridTextColumn Header="Schedule" Binding="{Binding Path=Sched}"/> 
      <DataGridTextColumn Header="ID" Binding="{Binding Path=ID}"/> 
      <DataGridTextColumn Header="OD" Binding="{Binding Path=OD}"/> 
      <DataGridTextColumn Header="Wall Thickness" Binding="{Binding Path=WT}" Width="*"/> 
     </DataGrid.Columns>      
    </DataGrid>   
</Grid> 

XML:私は新しいのObservableCollection毎回コンボを作成するため

<DBRoot> 
    <Mfg name="A Manufac"> 
    <pipe> 
     <Nominal>testdata</Nominal> 
     <Schedule>testdata</Schedule> 
     <OD>testdata</OD> 
     <Wall_Thickness>testdata</Wall_Thickness> 
     <ID>testdata</ID> 
    </pipe> 
    <pipe> 
     <Nominal>testdata</Nominal> 
     <Schedule>testdata</Schedule> 
     <OD>testdata</OD> 
     <Wall_Thickness>testdata</Wall_Thickness> 
     <ID>testdata</ID> 
    </pipe> 
    </Mfg> 
    <Mfg name="B Manufac"> 
    <pipe> 
     <Nominal>testdata</Nominal> 
     <Schedule>testdata</Schedule> 
     <OD>testdata</OD> 
     <Wall_Thickness>testdata</Wall_Thickness> 
     <ID>testdata</ID> 
    </pipe> 
    <pipe> 
     <Nominal>testdata</Nominal> 
     <Schedule>testdata</Schedule> 
     <OD>testdata</OD> 
     <Wall_Thickness>testdata</Wall_Thickness> 
     <ID>testdata</ID> 
    </pipe> 
    </Mfg> 
    </DBRoot> 

PopulateGrid呼び出しが遅いですボックスが値を変更します。私はコレクションやlinqを使って作業するのではなく、誰かが私のより堅牢な選択肢を提供できるなら、私はそれを感謝するだろう!

答えて

3

あなたはXMLファイルに直接結合することによって自分自身にいくつかの手間を省くことができます。

XAML

<Grid> 
    <Grid.DataContext> 
     <XmlDataProvider Source="DataBase.xml"/> 
    </Grid.DataContext> 

    <StackPanel> 
     <ComboBox ItemsSource="{Binding XPath=/DBRoot/Mfg}" Name="comboBox" SelectedIndex="0"> 
      <ComboBox.ItemTemplate> 
       <DataTemplate> 
        <TextBlock Text="{Binding [email protected]}"/> 
       </DataTemplate> 
      </ComboBox.ItemTemplate> 
     </ComboBox> 
     <DataGrid ItemsSource="{Binding ElementName=comboBox, Path=SelectedItem}" AutoGenerateColumns="False"> 
      <DataGrid.Columns> 
       <DataGridTextColumn Binding="{Binding XPath=Nominal}" Header="Nominal"/> 
       <DataGridTextColumn Binding="{Binding XPath=Schedule}" Header="Schedule"/> 
       <DataGridTextColumn Binding="{Binding XPath=OD}" Header="OD"/> 
       <DataGridTextColumn Binding="{Binding XPath=Wall_Thickness}" Header="Wall Thickness"/> 
       <DataGridTextColumn Binding="{Binding XPath=ID}" Header="ID"/> 
      </DataGrid.Columns> 
     </DataGrid> 
    </StackPanel> 
</Grid> 
+0

私はそれが「より良い」ものであるかどうか確信が持てなかったので、そのようにしていましたが、切り替えました。これを見ると、静的ファイルに直接結びつけるのがより理にかなっています。ありがとう! – neo

+0

それから、それを+1と答えてください。 – Paparazzi

+0

これにはフォローアップの質問があります。コンボリストに、XMLファイルに存在しない*項目を追加したいと思います。 「すべて」がアイテムであり、その結果、すべてのメーカーおよびパイプデータが表示されます。これを達成するためのプロパティを作成する必要がありますか? – neo

1

ああ私の良さ。問題はObservableCollection <文字列> MfgNamesで始まります。文字列にはインテリジェンスがなく、毎回ゼロからデータを構築しています。クラスを使用します。

public class Mfg 
{ 
    public string Name { get; private set; } 

    public ObservableCollection <CPipeData> pipes { .... 

は、次に詳細にあなただけのいくつかの製作所が同じパイプを使用する場合は、あなたが持つHas​​hSetのを作成しますMSDN.Microsoft.Com

にマスター・ディテールを見上げて

ItemsSounce="{binding ElementName=cbMfg Path=SelectedItem.Pipes}" 

をバインドそのハッシュセットをMfgに渡し、その単一のハッシュセットからLINQフィルタを使用します。 GetHashをオーバーライドします。

+0

私はあなたが気にしない場合は、もう少し知りたいです。いつどのように構築しますか?メーカーごとに独自のパイプセットがありますが、ユーザーはメーカーの「すべて」を見ることもできます。私は "Window_Loaded"関数でこのコードを実行し、コメントアウトしました。基本的にはObservableCollection of ObservableCollection を作成していました。私はこれが一度しか起こっていないが、まだかなり遅いことが分かった。 linqを正しい方法で実行する方法を知りたいと思います。あなたの意見では、別の投稿に表示されているように、XMLに直接バインドしていますか? – neo

+0

cbMfgにバインドする公開リストがあります。多くの場合、多くのLINQを必要とする必要はありません。あなたが必要とするパフォーマンスを得ているなら、ダンの答えを使ってください。私は+1しました。 – Paparazzi

+0

よかったです。ありがとう。 – neo

関連する問題