2015-04-01 18 views
0

WPF通常不是我的區域,所以我是一個新手,我有點麻煩了解如何在WPF中實現一些東西,這是一塊蛋糕在WinForms中。我似乎無法在這個論壇找到正確的主題,或者找到正確的YouTube教程,讓我找到答案。我有一個簡單的DataBinding到WPF文本框工作正常。我試圖實現的行爲是,對TextBox所做的任何更改都會立即反映在源類DataSet中。這是一個簡單的顯示/編輯場景,我確信有一個非常簡單的答案。WPF將文本框綁定到另一個類中的數據集

這是我怎麼會在的WinForms已經做到了....

表單代碼:

public partial class Form1 : Form 
{ 
    private DATARECORD CURRENTUSER; 

    public Form1() 
    { 
     InitializeComponent(); 
     CURRENTUSER = new DATARECORD(@"Data Source=C:\Users\rr187718\Documents\Personal\Programming\DynamicBackup\DynamicBackup\bin\Debug\Data\dbData.sdf"); 
     CURRENTUSER.FncBind(CtlCopiesToKeep, "Value", "tblUser.CopiesToKeep"); 
    } 

    //Test code to display the value in the DataSet 
    private void button1_Click(object sender, EventArgs e) 
    { 
     MessageBox.Show(CURRENTUSER.copiesToKeep.ToString()); 
    } 
} 

類代碼:

public class DATARECORD 
{ 
    private string ConnectionString; 
    private DataSet CurrentRecord; 
    public int copiesToKeep { get { return Int32.Parse(CurrentRecord.Tables["tblUser"].Rows[0]["CopiesToKeep"].ToString()); } } 

    public DATARECORD(string connectionString) 
    { 
     ConnectionString = connectionString; 
     CurrentRecord = new DataSet(); 
     SQL SQL = new SQL(2); 
     DataTable userTable = SQL.fncSelectAsTable(ConnectionString, "tblUser", "USERID=2"); 
     userTable.TableName = "tblUser"; 
     CurrentRecord.Tables.Add(userTable); 
     userTable.Dispose(); 
    } 

    public void FncBind(Control c, string type, string field) 
    { 
     c.DataBindings.Add(type, CurrentRecord, field, true, DataSourceUpdateMode.OnPropertyChanged); 
    } 
} 

然後我只是有主窗體上的簡單文本框稱爲「CtlCopiesToKeep」和「測試」按鈕。

有誰知道一個很好的,簡單的例子,可以顯示如何做到這一點?

許多在此先感謝, 戴夫

EDIT:

你好諾埃爾。非常感謝花時間解釋這一切。我已經把它放在一起,但是綁定似乎有些問題,因爲當我更改TextBox中的值時,它不會更新DataSet。這裏是代碼和XAML。如果任何人都可以指出我正確的方向,那麼將非常感激。

已更新的主要代碼

public partial class MainWindow : Window 
{ 
    public DATARECORD SELECTEDUSER; 
    private string ConnectionString = @"Data Source=C:\Users\rr187718\Documents\Personal\Programming\DynamicBackup\DynamicBackup\bin\Debug\Data\dbData.sdf"; 

    public MainWindow() 
    { 
     InitializeComponent(); 
     SELECTEDUSER = new DATARECORD(ConnectionString); 
     GrdMain.DataContext = SELECTEDUSER; 
    } 

    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     SELECTEDUSER.fncShowVals("BasePath"); 
    } 
} 

更新的類代碼

public class DATARECORD : INotifyPropertyChanged 
{ 
    private string ConnectionString; 
    private DataSet currentRecord = new DataSet(); 
    private string BasePath = null; 

    public string basePath 
    { 
     get 
     { 
      return currentRecord.Tables["tblStorage"].Rows[0]["BasePath"].ToString() ; 
     } 
     set 
     { 
      BasePath = value; 
      OnPropertyChanged("BasePath"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    public DATARECORD(string connectionString) 
    { 
     ConnectionString = connectionString; 
     SQL SQL = new SQL(ConnectionString, SQLVersion.CE); 
     DataTable storageTable = SQL.fncSelectAsTable(ConnectionString, "tblStorage", "USERID=2"); 
     storageTable.TableName = "tblStorage"; 
     currentRecord.Tables.Add(storageTable); 
     storageTable.Dispose(); 
    } 

    public void fncShowVals(string test) 
    { 
     MessageBox.Show(currentRecord.Tables["tblStorage"].Rows[0][test].ToString()); 
    } 

    protected void OnPropertyChanged(string value) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(value)); 
     } 
    } 

} 

XAML爲文本框

<Window x:Class="WpfBind.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="350" Width="525"> 
<Grid Name="GrdMain"> 
    <TextBox Text="{Binding basePath, Mode=TwoWay, UpdateSourceTrigger =PropertyChanged}" Height="23" HorizontalAlignment="Left" Margin="124,70,0,0" Name="CtlBaseFolder" VerticalAlignment="Top" Width="120" /> 
    <Label Content="BaseFolder" Height="28" HorizontalAlignment="Left" Margin="41,69,0,0" Name="label2" VerticalAlignment="Top" /> 
    <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="263,142,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" /> 
</Grid> 

UPDATE 2015年2月4日

我現在有這個,但我不明白它是如何引用數據集?此代碼生成一個空白文本框,如果該值發生變化,也不會更新數據集:

`private string ___basePath = null;

protected string _basePath 
    { 
     get 
     { 
      return ___basePath; 
     } 
     set 
     { 
      ___basePath = value; 
      OnPropertyChanged("basePath"); 
     } 
    } 

    public string basePath 
    { //<- Bind to this property 
     get 
     { 
      return ___basePath; 
     } 

     set 
     { 
      _basePath = value; 
     } 
    }` 

的基礎數據集的值存儲在這裏:提前

currentRecord.Tables["tblStorage"].Rows[0]["BasePath"].ToString(); 

非常感謝,戴夫。

更新 - 2015年2月4日 - 2

諾埃爾你好,我已應用的代碼,但它仍然沒有不幸的工作(如果我點擊數據集沒有反映在TextBox的變化「測試」按鈕)。這是整個代碼。順便說一句,我非常感謝你的時間,非常感謝!

public partial class MainWindow : Window 
{ 
    private string ConnectionString = @"Data Source=C:\Users\rr187718\Documents\Personal\Programming\DynamicBackup\DynamicBackup\bin\Debug\Data\dbData.sdf"; 
    private readonly DATARECORD _data = null; 
    public DATARECORD Data 
    { 
     get 
     { 
      return _data; 
     } 
    } 

    public MainWindow() 
    { 
     InitializeComponent(); 
     _data = new DATARECORD(ConnectionString); 
     DataContext = Data; //All controls connected to this class will now look for their value in 'Data' (DataContext inherits and must be a property because you can only bind to properties) 

    } 

    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     Data.fncShowVals("BasePath"); 
    } 
} 

public class DATARECORD : INotifyPropertyChanged 
{ 
    private string ConnectionString; 
    private DataSet currentRecord = new DataSet(); 

    private string ___basePath = null; 
    private string _basePath 
    { 
     get 
     { 
      if (___basePath == null) 
      { 
       //We only access the currentRecord if we did not yet stored the value 
       // otherwise it would read the currentRecord every time you type a char 
       // in the textbox. 
       // Also: Pay attention to multiple possible NullReferenceExceptions and IndexOutOfBoundsExceptions 
       ___basePath = currentRecord.Tables["tblStorage"].Rows[0]["BasePath"].ToString(); 
      } 

      return (___basePath == String.Empty) ? null : ___basePath; 
     } 
     set 
     { 
      ___basePath = (value == null) ? String.Empty : value; 
      NotifyPropertyChanged("BasePath"); 
     } 
    } 

    protected void PushBasePathToDataBase() 
    { 
     //Save the value of ___basePath to the database 
    } 

    public string BasePath 
    { //The Binding recieves/sets the Data from/to this property 
     get 
     { 
      return _basePath; 
     } 
     set 
     { 
      _basePath = value; 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    public DATARECORD(string connectionString) 
    { 
     ConnectionString = connectionString; 
     SQL SQL = new SQL(ConnectionString, SQLVersion.CE); 
     DataTable storageTable = SQL.fncSelectAsTable(ConnectionString, "tblStorage", "USERID=2"); 
     storageTable.TableName = "tblStorage"; 
     currentRecord.Tables.Add(storageTable); 
     storageTable.Dispose(); 
     ___basePath = currentRecord.Tables["tblStorage"].Rows[0]["BasePath"].ToString(); 
    } 

    public void fncShowVals(string test) 
    { 
     MessageBox.Show(currentRecord.Tables["tblStorage"].Rows[0][test].ToString()); 

    } 

    protected void NotifyPropertyChanged(string PropertyName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(PropertyName)); 
    } 
} 
+3

你能張貼您的XAML? – CoderForHire 2015-04-01 12:03:37

回答

0

很好,您正在使用綁定來從視覺效果分離數據。因爲這在winforms中是不可能的。爲了使綁定工作,你必須做到以下幾點:

  • 文本框必須有它的DataContext設置於保持綁定值類的實例。 DataContext = MyDataInstance;您可以在文本框本身或任何父級上設置它。

  • 您想要綁定的值以及DataContext必須是公共屬性。鐵:

    private string _name = null;

    public string Name{ get{ return _name; } set{ _name = value; NotifyPropertyChanged("Name"); } }

  • 數據類必須實現INotifyPropertyChanged

如果這是所有設置,你可以寫你的文本框在XAML:

<TextBlock Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 

Th Binding綁定到DataContext中指定的實例的Name屬性。它可以從屬性中檢索值,並且可以將數據寫入它。

  • 它臨危數據,當你調用你的數據類NotifyPropertyChanged("Name");
  • 它寫入數據時的控制變化的屬性(需要Mode設置爲TwoWayUpdateSourceTriggerPropertyChanged

EDIT(關於您的額外內容)
我注意到您想通知您的私人領域名爲"BasePath"
您必須通知酒店"basePath",而不是其後面的字段。
這就是爲什麼我建議一個嚴格的命名約定。

我的名字protected和private字段,如_privateOrProtected(1個下劃線)。
我爲受綁定屬性(如___someData(3個下劃線))和綁定屬性(如SomeData)訪問的私有或受保護字段命名。原因是,您通常不想直接設置私人字段,除非是綁定屬性的設置者。直接設置不會調用NotifyPropertyChanged();,這在幾乎所有情況下顯然都不是你想要的。如果你在應用程序中保留3個下劃線 - 每個人都有綁定的家庭應該很快理解其含義。

對於更復雜的數據,您可能需要綁定屬性來訪問訪問私有字段的私有/受保護屬性。我會這樣解決:SomeData,_someData,___someData。你只需要清楚它可以設置哪些屬性或字段來更新綁定,否則有人可能會更改___someData的值,並想知道綁定沒有更新的原因。

由於這是每個WPF應用程序中非常重要的一點,我真的希望您能夠理解它。這裏是上面的東西的例子:

private bool ___thisIsAwesome = true; 

protected bool _thisIsAwesome{ 
    get{ 
     return ___thisIsAwesome; 
    } 
    set{ 
     ___thisIsAwesome = value; 
     NotifyPropertyChanged("ThisIsAwesome"); 
    } 
} 

public bool ThisIsAwesome{ //<- Bind to this property 
    get{ 
     return ___thisIsAwesome; 
    } 
    /*set{ 
     _thisIsAwesome = value; 
    } NOTE: The setter is not accessable from outside of this class 
      because nobody can tell me that this is not awesome - it just is. 
      However I still want to be able to set the property correctly 
      from within my class (in case I change my mind), that is why I 
      added the protected property. 
      If you omit a getter/setter like this one make sure your 
      <br>Binding Mode</b> does not try to access the omited accessors. 
      Also check the output window too find possible binding errors 
      which never throw exceptions. 
    */ 
} 

在此代碼,你現在應該認識到,制定ThisIsAwesome_thisIsAwesome都將更新綁定。但要小心設置___thisIsAwesome,因爲它不會更新綁定。 ThisIsAwesome目前無法使用(無論什麼原因),這就是爲什麼我添加了受保護的屬性。你明白我想用它達到什麼嗎?

EDIT2(因爲你的代碼仍然不工作)

public partial class MainWindow : Window { 

     private readonly MyData _data = null; 
     public MyData Data{ 
      get{ 
       return _data; 
      } 
     } 

     public MainWindow() { 
      _data = new MyData(); 
      DataContext = Data; //All controls connected to this class will now look for their value in 'Data' (DataContext inherits and must be a property because you can only bind to properties) 
     } 
    } 



    public class MyData : INotifyPropertyChanged {  

     private string ___basePath = null; 
     private string _basePath { 
      get { 
       if (___basePath == null) { 
        //We only access the currentRecord if we did not yet stored the value 
        // otherwise it would read the currentRecord every time you type a char 
        // in the textbox. 
        // Also: Pay attention to multiple possible NullReferenceExceptions and IndexOutOfBoundsExceptions 
        ___basePath = currentRecord.Tables["tblStorage"].Rows[0]["BasePath"].ToString(); 
       } 

       return (___basePath == String.Empty) ? null : ___basePath; 
      } 
      set { 
       ___basePath = (value == null) ? String.Empty : value; 
       NotifyPropertyChanged("BasePath"); 
      } 
     } 

     protected void PushBasePathToDataBase() { 
      //Save the value of ___basePath to the database 
     } 

     public string BasePath{ //The Binding recieves/sets the Data from/to this property 
      get{ 
       return _basePath; 
      } 
      set{ 
       _basePath = value; 
      } 
     } 

     #region INotifyPropertyChanged 

     public event PropertyChangedEventHandler PropertyChanged; 

     protected void NotifyPropertyChanged(string PropertyName){ 
      if(PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs(PropertyName)); 
     } 

     #endregion INotifyPropertyChanged 
    } 

最後,在你的主窗口的XAML文本框:

<TextBlock Text="{Binding BasePath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 
+0

謝謝諾埃爾,我已經進一步瞭解了一些,並且已經發布了上面的新代碼和XAML。我會很感激你的想法,如何讓綁定100%的工作。非常感謝,Dave – 2015-04-01 15:28:36

+0

@ the_cat21您傳遞給OnPropertyChanged()的proerty名稱區分大小寫,「basepath」與「BasePath」不同。確保字符串等於您的財產的名稱或用戶界面不會對其執行操作。 – 2015-04-02 06:07:44

+0

@ the_cat21延長我的回答相當多 – 2015-04-02 06:47:02

相關問題