WPF 数据网格到 XML
WPF Datagrid to XML
我需要实际帮助。我正在尝试在 wpf 中编写一个用户可编辑的数据网格。我已经完成了大部分工作,但我仍然坚持将数据网格保存到 xml 并将其从 xml 加载到 wtf.
我会在我的代码中留下一些空白的“帮助评论”和一些关于我成功完成的事情的评论。考虑到我对 c# 和 wpf 没有任何先验知识,我为自己的成就感到非常自豪。可悲的是,我也是xml的新手,没有针对我的具体问题的好的教程material。
除保存和加载按钮外,所有按钮都可用。
这是XAML文件
<Window x:Class="WpfAppLunes.MainWindow" <!-- This changes according to project name -->
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfAppLunes" <!-- This changes according to project name -->
mc:Ignorable="d" FontSize="18"
Title="WPF_Lunes" Height="500" Width="800">
<Border Padding="10">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Row 0 -->
<!-- Title of the Application -->
<TextBlock x:Name="BigHeader" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" TextWrapping="Wrap" Margin="1" FontSize="36" FontWeight="Bold" Text="Monthly Transactions" />
<DataGrid Grid.Row="1" AutoGenerateColumns="False" CanUserAddRows="False" x:Name="dgContent">
<DataGrid.Columns>
<DataGridTextColumn Header="Transaction Name" Binding="{Binding transactionName}"/>
<DataGridTextColumn Header="Amount '$'" Binding="{Binding Amount}"/>
</DataGrid.Columns>
</DataGrid>
<!--
<ListView Margin="10" Name="lvUsers" Grid.Row="1" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn Header="Transaction Name" DisplayMemberBinding="{Binding transactionName}" />
<GridViewColumn Header="Amount '$'" DisplayMemberBinding="{Binding Amount}" />
</GridView>
</ListView.View>
</ListView>
-->
<TextBlock x:Name="TransactionHeader" Grid.Row="3" Grid.Column="0" TextWrapping="Wrap" Margin="1" Text="Transaction Name" />
<TextBlock x:Name="AmountHeader" Grid.Row="3" Grid.Column="1" TextWrapping="Wrap" Margin="1" Text="Amount" />
<!-- Row 3 -->
<!-- Text Boxes for the user to declare next item and its price -->
<TextBox x:Name="newTransaction" Grid.Row="4" Grid.Column="0" Padding="5" Margin="5"/>
<TextBox x:Name="newAmount" Grid.Row="4" Grid.Column="1" Padding="5" Margin="5" PreviewTextInput="newAmount_PreviewTextInput"/>
<ComboBox Grid.Row="4" Grid.Column="2" Name="Language" Width="170" Margin="1" VerticalContentAlignment="Center" VerticalAlignment="Top" MaxDropDownHeight="auto"></ComboBox>
<!-- <TextBox Text="{Binding Path=value, StringFormat={}{0:#.##}}" /> -->
<!-- Row 4 -->
<!-- Buttons to Add to the list or delete from the list -->
<Button x:Name="addButton" Click="addButton_Click" Grid.Row="5" Grid.Column="0" Margin="10" Content="Add" />
<Button x:Name="deleteButton" Click="deleteButton_Click" Grid.Row="5" Grid.Column="1" Margin="10" Content="Delete" />
<Button x:Name="changeButton" Content="Dil Değiştir" Margin="10" Grid.Column="3" Grid.Row="5" Click="changeButton_Click"/>
<!-- Row 5 -->
<!-- Save or Load the file -->
<Button x:Name="saveButton" Click="saveButton_Click" Grid.Row="6" Grid.Column="0" Margin="10" Content="Save" />
<Button x:Name="loadButton" Click="loadButton_Click" Grid.Row="6" Grid.Column="1" Margin="10" Content="Load" />
<!--Row 7 test for localization -->
</Grid>
</Border>
这是 c# 文件。
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Finisar.SQLite;
using System.Xml;
using System.Xml.Linq;
using System.IO;
//I tried to use a lot of stuffs and did not bother to remove them. If you add another, put a comment
//next to it please.
namespace WpfAppLunes
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
//I initialize my datagrid here.
ObservableCollection<transaction> myObjects;
public MainWindow()
{
InitializeComponent();
myObjects = new ObservableCollection<transaction>()
{
new transaction(){transactionName = "Salary", Amount = ",670.00"},
new transaction(){transactionName = "Car", Amount = "-.00"},
new transaction(){transactionName = "Clothing", Amount = "-0.00"},
new transaction(){transactionName = "Food", Amount = "-.00"},
new transaction(){transactionName = "Leisure", Amount = "-.00"},
new transaction(){transactionName = "Living", Amount = "-0.00"}
};
this.dgContent.ItemsSource = myObjects;
BindLanguage();
}
//This is my combobox that lets the user choose from language settings
#region Bind Language From and To Combobox
private void BindLanguage()
{
DataTable dtCurrency = new DataTable();
//Add display column in DataTable
dtCurrency.Columns.Add("Text");
//Add value column in DataTable
dtCurrency.Columns.Add("Value");
dtCurrency.Rows.Add("EN", 0);
dtCurrency.Rows.Add("TR", 1);
Language.ItemsSource = dtCurrency.DefaultView;
Language.DisplayMemberPath = "Text";
Language.SelectedValuePath = "Value";
Language.SelectedIndex = 0;
}
#endregion
//It adds the transaction name and value to the data grid. It also formats the datagrid amount view.
//Add button properties
private void addButton_Click(object sender, RoutedEventArgs e)
{
double amountFormat;
amountFormat = double.Parse(this.newAmount.Text);
if (amountFormat < 0)
{
amountFormat *= -1;
transaction myObject = new transaction() { transactionName = this.newTransaction.Text, Amount = "-$" + amountFormat.ToString("N2") };
myObjects.Add(myObject);
}
else
{
transaction myObject = new transaction() { transactionName = this.newTransaction.Text, Amount = "$" + amountFormat.ToString("N2") };
myObjects.Add(myObject);
}
}
//It deletes the selected value from the data grid.
//Delete button properties
private void deleteButton_Click(object sender, RoutedEventArgs e)
{
if (dgContent.SelectedIndex >= 0)
{
//remove the selectedItem from the collection source
transaction selected = dgContent.SelectedItem as transaction;
myObjects.Remove(selected);
}
}
//Save button properties
private void saveButton_Click(object sender, RoutedEventArgs e)
{
/* HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP */
}
//Load button properties
//I thought it would be good idea to clear the datagrid before I actually load the file from xml
//I think it will be good idea to create a new button just to clear the datagrid. I will add it later.
private void loadButton_Click(object sender, RoutedEventArgs e)
{
/* HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP */
myObjects.Clear();
}
//It gets the textbox values.
public class transaction
{
public string transactionName { get; set; }
public string Amount { get; set; }
}
//Makes sure that user can input only the +/- decimal values.
private void newAmount_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
//Because this line and next line comes before regex, they can be inputted.
//It will allow the user to add negative value
if (e.Text.Equals("-") && newAmount.Text.Length.Equals(0))
return;
//It will allow the user input 1 decimal point.
//User can input more than 2 numbers after the decimal point to my displeasure
//I did manage to get a workaround on this though. When the amount is added to the datagrid
//it will show in the way I want it to show.
if (e.Text.Equals(".") && !newAmount.Text.Contains("."))
return;
//This makes sure that user cannot enter anything other than number.
Regex regex = new Regex("[^0-9]+");
e.Handled = regex.IsMatch(e.Text);
}
//It is my localization method.
//This is my version of localization. I could not get xaml change language because it would not recognize
//loc type variables for some reason. Maybe I missed some library. :D
//I would love it if someone told me the possible problem, but it is my last concern.
private void changeButton_Click(object sender, RoutedEventArgs e)
{
if (Language.Text == "EN" && changeButton.Content.ToString() == "Change Language")
{
changeButton.Content = "Dil Değiştir";
addButton.Content = "Add";
deleteButton.Content = "Delete";
saveButton.Content = "Save";
loadButton.Content = "Load";
TransactionHeader.Text = "Transaction Name";
AmountHeader.Text = "Amount";
dgContent.Columns[0].Header = "Transaction Name";
dgContent.Columns[1].Header = "Amount '$'";
BigHeader.Text = "Monthly Transactions";
}
if(Language.Text == "TR" && changeButton.Content.ToString() == "Dil Değiştir")
{
changeButton.Content = "Change Language";
addButton.Content = "Ekle";
deleteButton.Content = "Sil";
saveButton.Content = "Kaydet";
loadButton.Content = "Yükle";
TransactionHeader.Text = "İşlem";
AmountHeader.Text = "İşlem Miktarı";
dgContent.Columns[0].Header = "İşlem";
dgContent.Columns[1].Header = "İşlem Miktarı '$'";
BigHeader.Text = "Aylık Gelir/Giderler";
}
}
}
}
---代码结束---
我已经删除了我试图实现的代码并将它们注释掉。我害羞了。
我真的很感激它是一个已实施或可以在我的评论中实施的实际代码。我已经在网上看了几个小时了。我快气疯了。
对于 serialize/deserialize 对象 to/from XML,您必须使用 XmlSerializer class。
我不知道您必须使用的 XML 格式,所以我想您不介意。
此代码将从名为 mydata.xml
的桌面文件中 save/load 数据
//Save button properties
private void saveButton_Click(object sender, RoutedEventArgs e)
{
var fileName = GetSaveFilePath();
var serializer = new XmlSerializer(typeof(List<transaction>));
using (TextWriter stream = new StreamWriter(fileName))
{
serializer.Serialize(stream, myObjects.ToList());
stream.Flush();
}
}
/// <summary>
/// Where you want to save data
/// </summary>
private string GetSaveFilePath()
{
var desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
var fileName = System.IO.Path.Combine(desktop, "myData.xml");
return fileName;
}
//Load button properties
private void loadButton_Click(object sender, RoutedEventArgs e)
{
myObjects.Clear();
var fileName = GetSaveFilePath();
var serializer = new XmlSerializer(typeof(List<transaction>));
using (TextReader stream = new StreamReader(fileName))
{
var list = (List<transaction>)serializer.Deserialize(stream);
foreach (var item in list)
{
myObjects.Add(item);
}
}
}
我需要实际帮助。我正在尝试在 wpf 中编写一个用户可编辑的数据网格。我已经完成了大部分工作,但我仍然坚持将数据网格保存到 xml 并将其从 xml 加载到 wtf.
我会在我的代码中留下一些空白的“帮助评论”和一些关于我成功完成的事情的评论。考虑到我对 c# 和 wpf 没有任何先验知识,我为自己的成就感到非常自豪。可悲的是,我也是xml的新手,没有针对我的具体问题的好的教程material。
除保存和加载按钮外,所有按钮都可用。
这是XAML文件
<Window x:Class="WpfAppLunes.MainWindow" <!-- This changes according to project name -->
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfAppLunes" <!-- This changes according to project name -->
mc:Ignorable="d" FontSize="18"
Title="WPF_Lunes" Height="500" Width="800">
<Border Padding="10">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Row 0 -->
<!-- Title of the Application -->
<TextBlock x:Name="BigHeader" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" TextWrapping="Wrap" Margin="1" FontSize="36" FontWeight="Bold" Text="Monthly Transactions" />
<DataGrid Grid.Row="1" AutoGenerateColumns="False" CanUserAddRows="False" x:Name="dgContent">
<DataGrid.Columns>
<DataGridTextColumn Header="Transaction Name" Binding="{Binding transactionName}"/>
<DataGridTextColumn Header="Amount '$'" Binding="{Binding Amount}"/>
</DataGrid.Columns>
</DataGrid>
<!--
<ListView Margin="10" Name="lvUsers" Grid.Row="1" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn Header="Transaction Name" DisplayMemberBinding="{Binding transactionName}" />
<GridViewColumn Header="Amount '$'" DisplayMemberBinding="{Binding Amount}" />
</GridView>
</ListView.View>
</ListView>
-->
<TextBlock x:Name="TransactionHeader" Grid.Row="3" Grid.Column="0" TextWrapping="Wrap" Margin="1" Text="Transaction Name" />
<TextBlock x:Name="AmountHeader" Grid.Row="3" Grid.Column="1" TextWrapping="Wrap" Margin="1" Text="Amount" />
<!-- Row 3 -->
<!-- Text Boxes for the user to declare next item and its price -->
<TextBox x:Name="newTransaction" Grid.Row="4" Grid.Column="0" Padding="5" Margin="5"/>
<TextBox x:Name="newAmount" Grid.Row="4" Grid.Column="1" Padding="5" Margin="5" PreviewTextInput="newAmount_PreviewTextInput"/>
<ComboBox Grid.Row="4" Grid.Column="2" Name="Language" Width="170" Margin="1" VerticalContentAlignment="Center" VerticalAlignment="Top" MaxDropDownHeight="auto"></ComboBox>
<!-- <TextBox Text="{Binding Path=value, StringFormat={}{0:#.##}}" /> -->
<!-- Row 4 -->
<!-- Buttons to Add to the list or delete from the list -->
<Button x:Name="addButton" Click="addButton_Click" Grid.Row="5" Grid.Column="0" Margin="10" Content="Add" />
<Button x:Name="deleteButton" Click="deleteButton_Click" Grid.Row="5" Grid.Column="1" Margin="10" Content="Delete" />
<Button x:Name="changeButton" Content="Dil Değiştir" Margin="10" Grid.Column="3" Grid.Row="5" Click="changeButton_Click"/>
<!-- Row 5 -->
<!-- Save or Load the file -->
<Button x:Name="saveButton" Click="saveButton_Click" Grid.Row="6" Grid.Column="0" Margin="10" Content="Save" />
<Button x:Name="loadButton" Click="loadButton_Click" Grid.Row="6" Grid.Column="1" Margin="10" Content="Load" />
<!--Row 7 test for localization -->
</Grid>
</Border>
这是 c# 文件。
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Finisar.SQLite;
using System.Xml;
using System.Xml.Linq;
using System.IO;
//I tried to use a lot of stuffs and did not bother to remove them. If you add another, put a comment
//next to it please.
namespace WpfAppLunes
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
//I initialize my datagrid here.
ObservableCollection<transaction> myObjects;
public MainWindow()
{
InitializeComponent();
myObjects = new ObservableCollection<transaction>()
{
new transaction(){transactionName = "Salary", Amount = ",670.00"},
new transaction(){transactionName = "Car", Amount = "-.00"},
new transaction(){transactionName = "Clothing", Amount = "-0.00"},
new transaction(){transactionName = "Food", Amount = "-.00"},
new transaction(){transactionName = "Leisure", Amount = "-.00"},
new transaction(){transactionName = "Living", Amount = "-0.00"}
};
this.dgContent.ItemsSource = myObjects;
BindLanguage();
}
//This is my combobox that lets the user choose from language settings
#region Bind Language From and To Combobox
private void BindLanguage()
{
DataTable dtCurrency = new DataTable();
//Add display column in DataTable
dtCurrency.Columns.Add("Text");
//Add value column in DataTable
dtCurrency.Columns.Add("Value");
dtCurrency.Rows.Add("EN", 0);
dtCurrency.Rows.Add("TR", 1);
Language.ItemsSource = dtCurrency.DefaultView;
Language.DisplayMemberPath = "Text";
Language.SelectedValuePath = "Value";
Language.SelectedIndex = 0;
}
#endregion
//It adds the transaction name and value to the data grid. It also formats the datagrid amount view.
//Add button properties
private void addButton_Click(object sender, RoutedEventArgs e)
{
double amountFormat;
amountFormat = double.Parse(this.newAmount.Text);
if (amountFormat < 0)
{
amountFormat *= -1;
transaction myObject = new transaction() { transactionName = this.newTransaction.Text, Amount = "-$" + amountFormat.ToString("N2") };
myObjects.Add(myObject);
}
else
{
transaction myObject = new transaction() { transactionName = this.newTransaction.Text, Amount = "$" + amountFormat.ToString("N2") };
myObjects.Add(myObject);
}
}
//It deletes the selected value from the data grid.
//Delete button properties
private void deleteButton_Click(object sender, RoutedEventArgs e)
{
if (dgContent.SelectedIndex >= 0)
{
//remove the selectedItem from the collection source
transaction selected = dgContent.SelectedItem as transaction;
myObjects.Remove(selected);
}
}
//Save button properties
private void saveButton_Click(object sender, RoutedEventArgs e)
{
/* HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP */
}
//Load button properties
//I thought it would be good idea to clear the datagrid before I actually load the file from xml
//I think it will be good idea to create a new button just to clear the datagrid. I will add it later.
private void loadButton_Click(object sender, RoutedEventArgs e)
{
/* HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP HELP */
myObjects.Clear();
}
//It gets the textbox values.
public class transaction
{
public string transactionName { get; set; }
public string Amount { get; set; }
}
//Makes sure that user can input only the +/- decimal values.
private void newAmount_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
//Because this line and next line comes before regex, they can be inputted.
//It will allow the user to add negative value
if (e.Text.Equals("-") && newAmount.Text.Length.Equals(0))
return;
//It will allow the user input 1 decimal point.
//User can input more than 2 numbers after the decimal point to my displeasure
//I did manage to get a workaround on this though. When the amount is added to the datagrid
//it will show in the way I want it to show.
if (e.Text.Equals(".") && !newAmount.Text.Contains("."))
return;
//This makes sure that user cannot enter anything other than number.
Regex regex = new Regex("[^0-9]+");
e.Handled = regex.IsMatch(e.Text);
}
//It is my localization method.
//This is my version of localization. I could not get xaml change language because it would not recognize
//loc type variables for some reason. Maybe I missed some library. :D
//I would love it if someone told me the possible problem, but it is my last concern.
private void changeButton_Click(object sender, RoutedEventArgs e)
{
if (Language.Text == "EN" && changeButton.Content.ToString() == "Change Language")
{
changeButton.Content = "Dil Değiştir";
addButton.Content = "Add";
deleteButton.Content = "Delete";
saveButton.Content = "Save";
loadButton.Content = "Load";
TransactionHeader.Text = "Transaction Name";
AmountHeader.Text = "Amount";
dgContent.Columns[0].Header = "Transaction Name";
dgContent.Columns[1].Header = "Amount '$'";
BigHeader.Text = "Monthly Transactions";
}
if(Language.Text == "TR" && changeButton.Content.ToString() == "Dil Değiştir")
{
changeButton.Content = "Change Language";
addButton.Content = "Ekle";
deleteButton.Content = "Sil";
saveButton.Content = "Kaydet";
loadButton.Content = "Yükle";
TransactionHeader.Text = "İşlem";
AmountHeader.Text = "İşlem Miktarı";
dgContent.Columns[0].Header = "İşlem";
dgContent.Columns[1].Header = "İşlem Miktarı '$'";
BigHeader.Text = "Aylık Gelir/Giderler";
}
}
}
}
---代码结束--- 我已经删除了我试图实现的代码并将它们注释掉。我害羞了。
我真的很感激它是一个已实施或可以在我的评论中实施的实际代码。我已经在网上看了几个小时了。我快气疯了。
对于 serialize/deserialize 对象 to/from XML,您必须使用 XmlSerializer class。 我不知道您必须使用的 XML 格式,所以我想您不介意。
此代码将从名为 mydata.xml
的桌面文件中 save/load 数据 //Save button properties
private void saveButton_Click(object sender, RoutedEventArgs e)
{
var fileName = GetSaveFilePath();
var serializer = new XmlSerializer(typeof(List<transaction>));
using (TextWriter stream = new StreamWriter(fileName))
{
serializer.Serialize(stream, myObjects.ToList());
stream.Flush();
}
}
/// <summary>
/// Where you want to save data
/// </summary>
private string GetSaveFilePath()
{
var desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
var fileName = System.IO.Path.Combine(desktop, "myData.xml");
return fileName;
}
//Load button properties
private void loadButton_Click(object sender, RoutedEventArgs e)
{
myObjects.Clear();
var fileName = GetSaveFilePath();
var serializer = new XmlSerializer(typeof(List<transaction>));
using (TextReader stream = new StreamReader(fileName))
{
var list = (List<transaction>)serializer.Deserialize(stream);
foreach (var item in list)
{
myObjects.Add(item);
}
}
}