使用inotifypropertychanged C#WPF更新包含多个字符串的文本框 [英] Updating textbox with multiple strings using inotifypropertychanged C# WPF
问题描述
美好的一天,
我对C#相对较新,并且刚刚实现了INotifypropertychanged。
我正在研究从CANbus读取ECU数据的项目,当我收到数据时,我正在使用INotifypropertychanged来更新带有接收数据的UI 。
这种方法运行良好而且快速但是每次收到数据时,都会覆盖previos数据(显然) - 有没有办法将数据存储在列表或调用中propertychanged每次都在文本框的新/下一行打印?
谢谢
< b>我尝试了什么:
尝试创建一个可观察的集合,但无法更新列表。
下面的示例应该适用于ListView - 您可以使用列表框轻松替换listview。如果您对此有任何疑问,请告诉我。
使用系统;
使用 System.Windows;
使用 System.Windows.Controls;
使用 System.Collections.ObjectModel;
命名空间 ListViewTest.Test2
{
public partial class ListViewTest:Window
{
/// < 摘要 >
/// ObservableCollection用于存储listview中显示的数据
/// < / summary >
ObservableCollection< ; GAMEDATA> _GameCollection = new ObservableCollection< GameData>();
/// < 摘要 >
/// 标准构造函数填写ListView
/// via Observable collection with three items
/// < span class =code-summarycomment>< / summary >
public ListViewTest()
{
_GameCollection.Add( new GameData
{
GameName = 魔兽世界,
Creator = 暴雪,
发布者= 暴雪
});
_GameCollection.Add( new GameData
{
GameName = Halo,
Creator = Bungie,
发布者= Microsoft
});
_GameCollection.Add( new GameData
{
GameName = Gears Of War,
Creator = Epic,
Publisher = Microsoft
});
InitializeComponent();
}
public ObservableCollection< GameData> GameCollection
{
get { return _GameCollection; }
}
/// < 摘要 >
/// 点击按钮事件向ObservableCollection添加新元素
/// - >该事件被转发到listview
/// 稍后会显示更改...
/// < / summary >
/// < param < span class =code-summarycomment> name =sender > < / param >
/// < param name =e > < / param > ;
private void AddRow_Click( object sender,RoutedEventArgs e)
{
_GameCollection.Add( new GameData
{
GameName = 新游戏,
Creator = 新造物主,
发布者= 新发布商
});
}
}
/// < 摘要 >
/// 要存储在ObservableCollection中并在Listview中显示的简单类
/// < / summary >
public class GameData
{
public string GameName { get ; set ; }
public string 创建者{ get 跨度>; set ; }
public string 发布商{ get 跨度>; set ; }
}
}
< 窗口 x:Class = ListViewTest.Test2.ListViewTest
xmlns = < span class =code-keyword> http://schemas.microsoft.com/winfx/2006/xaml/presentation
< span class =code-attribute>
xmlns:x = HTTP: //schemas.microsoft.com/winfx/2006/xaml\"
DataContext = {Binding RelativeSource = {RelativeSource Self}}
标题 = 某些游戏数据 高度 = 216 宽度 = 435 >
< 网格 >
< ; Grid.RowDefinitions >
< RowDefinition 高度 = 自动 / >
< < span class =code-leadattribute> RowDefinition 高度 = 自动 / >
< / Grid.RowDefinitions >
< span class =code-keyword>< TextBlock Grid.Row = 0 TextWrapping = WrapWithOverflow 保证金 = < span class =code-keyword> 3 >
这说明如何在XAML中使用静态信息来实现ListView(请参阅ListView项目)
以及如何填充信息在ListView中通过绑定数据源使用
< TextBlock FontWeight = 粗体 > ObservableCollection < / TextBlock >
(请参阅ListViewTest项目)。
< / TextBlock >
< StackPanel Grid.Row = 1 >
< ListView ItemsSource = {Binding GameCollection} >
< ; ListView.View >
< GridView >
< GridViewColumn < span class =code-attribute> 宽度 = 140 标题 = 游戏名称 DisplayMemberBinding = {Binding GameName} / >
< span class =code-keyword>< GridViewColumn 宽度 = 140 标题 = 创建者 DisplayMemberBinding = {Binding Creator} / >
< GridViewColumn 宽度 = 140 标题 = 发布商 DisplayMemberBinding = {绑定发布者} / >
< / GridView > ;
< / ListView.View >
< / ListView >
< 按钮 HorizontalAlignment = 右 < span class =code-attribute>保证金 = 5,5,5,5
内容 = 添加行 点击 < span class =code-keyword> = AddRow_Click / >
< / StackPanel >
< / Grid >
< / Window >
< blockquote> @Dirk,
请看下面,我试图做一个简单的应用程序突出显示问题,
- Mainwindow创建一个实例MainViewModel创建TcpConnection类的实例。
- 可观察集合在TcpConnection类中创建
- 在测试期间将数据添加到可观察集合_CanMessage
- 但它永远不会更新到绑定Listview
我不完全确定xaml中的绑定名称所以可能会有问题..
如果您有任何其他问题,请与我们联系。
使用系统;
使用 System.Collections.Generic;
使用 System.Collections.ObjectModel;
使用 System.ComponentModel;
使用 System.Net.Sockets;
使用 System.Threading;
使用 System.Windows;
使用 静态 SampleProj.MainViewModel;
命名空间 SampleProj
{
public partial class MainWindow:Window
{
MainViewModel _main;
public MainWindow()
{
InitializeComponent();
_main = new MainViewModel();
DataContext = _main;
}
private void Connect_Button_Click( object sender,RoutedEventArgs e)
{
_main.Client.Connect();
}
private void Start_Button_Click( object sender,RoutedEventArgs e)
{
byte [] data = { 42 , 0 , 17 , 2 , 0 , 22 , 0 , 0 , 22 , 43 };
_main.Client.Write(data);
}
}
类 MainViewModel:ObservableObject
{
public TcpConnection Client { get ; private set ; }
public MainViewModel()
{
Client = new TcpConnection();
}
public class 消息
{
public string CANMessage { get ; set ; }
}
}
public class TcpConnection :ObservableObject
{
TcpClient客户端;
Thread threadClientReceive;
NetworkStream clientStream;
ObservableCollection< Message> _CanMessage = new ObservableCollection< Message>();
bool receiveThreadAlive = false ;
bool flagThreadRunning = false ;
bool clientIsConnected = false ;
string identifier = string .Empty;
string data = string .Empty;
public TcpConnection()
{
}
public void Connect()
{
client = new TcpClient();
var result = client.BeginConnect( 192.168.0.1, 10000 , null ,空跨度>);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds( 2 ));
threadClientReceive = new 线程( new ParameterizedThreadStart(TcpReceive));
flagThreadRunning = true ;
receiveThreadAlive = true ;
threadClientReceive.Start(client);
if (!success)
{
throw new 异常();
}
if (client.Connected)
{
clientIsConnected = 真跨度>;
}
}
public void TcpReceive( object client)
{
string bitString = 串跨度> .Empty;
bool startBitFound = false ;
byte startBit = 42 ;
byte stopBit = 43 ;
列表< byte> receiveDataList = new List< byte>();
TcpClient tcpClient =(TcpClient)客户端;
if (tcpClient.Connected)
{
clientStream = tcpClient.GetStream();
}
byte [] buffer = new byte [ 1024 ];
while (flagThreadRunning)
{
int bytesRead = 0 跨度>;
try
{
bytesRead = clientStream.Read(buffer, 0 ,buffer.Length);
}
catch {}
if ( bytesRead == 0 )
{
break ;
}
for ( int i = 0 ; i < buffer.Length; i ++)
{
if (buffer [i] == startBit)
{
startBitFound = true ;
}
if (startBitFound)
{
receiveDataList.Add(buffer [i]);
}
if (buffer [i] == stopBit)
{
if (receiveDataList.Count == 0 )
break 跨度>;
else
{
string message = HexEncoding.ToString(receiveDataList .ToArray());
if (message.Length > 0 )
{
_CanMessage.Add( new Message {CANMessage = message});
}
startBitFound = false ;
receiveDataList.Clear();
break ;
}
}
}
}
}
public void 写( byte [] data)
{
clientStream = client.GetStream();
尝试
{
clientStream.Write(data, 0 , data.Length);
}
catch
{
}
}
}
public class HexEncoding
{
public HexEncoding()
{
}
public static string ToString( byte [] bytes)
{
string hexString = 跨度>;
for ( int i = 0 ; i < bytes.Length; i ++)
{
hexString + = bytes [i] .ToString(< span class =code-string> X2);
}
return hexString;
}
}
public class ObservableObject:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
受保护 void OnPropertyChanged( string propertyName)
{
PropertyChanged?.Invoke( this , new PropertyChangedEventArgs(propertyName));
}
}
}
< Window x:Class = SampleProj.MainWindow
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:SampleProj
DataContext = {Binding RelativeSource = {RelativeSource Self}}
mc:Ignorable = d
Title = MainWindow高度= 600宽度= 525 >
< Grid Margin = 0,0,-6.6,-242.2 >
< Button Name=\"conect\" Content= \"Connect\" HorizontalAlignment=\"Left\" Margin=\"119,37 ,0,0\" VerticalAlignment=\"Top\" Width=\"75\" Click=\"Connect_Button_Click\"/>
<Button Name = \"start\" Content=\"Start Session\" HorizontalAlignment=\"Left\" Margin=\"240,37,0,0\" VerticalAlignment=\"Top\" Width=\"100\" Click=\"Start_Button_Click\"/>
<ListView ItemsSource = \"{Binding Message}\" Grid.ColumnSpan=\"5\" Grid.Column=\"2\" HorizontalAlignment=\"Left\" Height=\"489\" Margin=\"29.4,65.6,0,0\" Grid.Row=\"2\" Grid.RowSpan=\"11\" VerticalAlignment=\"Top\" Width=\"429\">
<ListView.View>
<GridView>
<GridViewColumn Width = \" 200\" Header=\"Message\" DisplayMemberBinding=\"{Binding CANMessage}\" ></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
Good day,
I am relatively new to C# and have just got the hang of implementing INotifypropertychanged.
I am working on a project reading data off an ECU from the CANbus, and as I receive the data I am currently using INotifypropertychanged to update the UI with the received data.
This works well and fast however each time data is received, the previos data is overwritten(obviously) - is there any way to store the data in a list or call propertychanged to print in a new/next line of the textbox each time??
Thanks
What I have tried:
Tried creating an observable collection but was not able to update the list.
The sample below should work for a ListView - you can easily replace the listview with a listbox. Let me know if you have questions about it.
using System; using System.Windows; using System.Windows.Controls; using System.Collections.ObjectModel; namespace ListViewTest.Test2 { public partial class ListViewTest : Window { /// <summary> /// ObservableCollection to store data displayed in listview /// </summary> ObservableCollection<GameData> _GameCollection = new ObservableCollection<GameData>(); /// <summary> /// Standard Constructor fills up the ListView /// via Observable collection with three items /// </summary> public ListViewTest() { _GameCollection.Add(new GameData { GameName = "World Of Warcraft", Creator = "Blizzard", Publisher = "Blizzard" }); _GameCollection.Add(new GameData { GameName = "Halo", Creator = "Bungie", Publisher = "Microsoft" }); _GameCollection.Add(new GameData { GameName = "Gears Of War", Creator = "Epic", Publisher = "Microsoft" }); InitializeComponent(); } public ObservableCollection<GameData> GameCollection { get { return _GameCollection; } } /// <summary> /// Click button event adds a new element to the ObservableCollection /// each time the button is clicked -> the event is forwarded to listview /// which displays the change later on... /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void AddRow_Click(object sender, RoutedEventArgs e) { _GameCollection.Add(new GameData { GameName = "A New Game", Creator = "A New Creator", Publisher = "A New Publisher" }); } } /// <summary> /// Simple class to be stored in ObservableCollection and to be displayed in Listview /// </summary> public class GameData { public string GameName { get; set; } public string Creator { get; set; } public string Publisher { get; set; } } }
<Window x:Class="ListViewTest.Test2.ListViewTest" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" DataContext="{Binding RelativeSource={RelativeSource Self}}" Title="Some Game Data" Height="216" Width="435"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <TextBlock Grid.Row="0" TextWrapping="WrapWithOverflow" Margin="3"> This smaple demonstates how to implment a ListView with static information in XAML (see ListView project) and how to populate information in a ListView via bound data source using an <TextBlock FontWeight="Bold">ObservableCollection</TextBlock> (see ListViewTest project). </TextBlock> <StackPanel Grid.Row="1"> <ListView ItemsSource="{Binding GameCollection}"> <ListView.View> <GridView> <GridViewColumn Width="140" Header="Game Name" DisplayMemberBinding="{Binding GameName}" /> <GridViewColumn Width="140" Header="Creator" DisplayMemberBinding="{Binding Creator}" /> <GridViewColumn Width="140" Header="Publisher" DisplayMemberBinding="{Binding Publisher}" /> </GridView> </ListView.View> </ListView> <Button HorizontalAlignment="Right" Margin="5,5,5,5" Content="Add Row" Click="AddRow_Click" /> </StackPanel> </Grid> </Window>
@Dirk,
Please see below, I have tried to make a simple application highlighting the issue,
- Mainwindow creates an instance of MainViewModel which creates an instance of the TcpConnection class.
- The observable collection is created in the TcpConnection class
- data is added to the observable collection "_CanMessage" during testing
- however its is never updated to the bound Listview
I am not entirely sure about the binding names in the xaml so there could be the issue..
Please let me know if you have any further questions.
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Net.Sockets; using System.Threading; using System.Windows; using static SampleProj.MainViewModel; namespace SampleProj { public partial class MainWindow : Window { MainViewModel _main; public MainWindow() { InitializeComponent(); _main = new MainViewModel(); DataContext = _main; } private void Connect_Button_Click(object sender, RoutedEventArgs e) { _main.Client.Connect(); } private void Start_Button_Click(object sender, RoutedEventArgs e) { byte[] data = { 42, 0, 17, 2, 0, 22, 0, 0, 22, 43 }; _main.Client.Write(data); } } class MainViewModel : ObservableObject { public TcpConnection Client { get; private set; } public MainViewModel() { Client = new TcpConnection(); } public class Message { public string CANMessage { get; set; } } } public class TcpConnection : ObservableObject { TcpClient client; Thread threadClientReceive; NetworkStream clientStream; ObservableCollection<Message> _CanMessage = new ObservableCollection<Message>(); bool receiveThreadAlive = false; bool flagThreadRunning = false; bool clientIsConnected = false; string identifier = string.Empty; string data = string.Empty; public TcpConnection() { } public void Connect() { client = new TcpClient(); var result = client.BeginConnect("192.168.0.1", 10000, null, null); var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(2)); threadClientReceive = new Thread(new ParameterizedThreadStart(TcpReceive)); flagThreadRunning = true; receiveThreadAlive = true; threadClientReceive.Start(client); if (!success) { throw new Exception(); } if (client.Connected) { clientIsConnected = true; } } public void TcpReceive(object client) { string bitString = string.Empty; bool startBitFound = false; byte startBit = 42; byte stopBit = 43; List<byte> receiveDataList = new List<byte>(); TcpClient tcpClient = (TcpClient)client; if (tcpClient.Connected) { clientStream = tcpClient.GetStream(); } byte[] buffer = new byte[1024]; while (flagThreadRunning) { int bytesRead = 0; try { bytesRead = clientStream.Read(buffer, 0, buffer.Length); } catch { } if (bytesRead == 0) { break; } for (int i = 0; i < buffer.Length; i++) { if (buffer[i] == startBit) { startBitFound = true; } if (startBitFound) { receiveDataList.Add(buffer[i]); } if (buffer[i] == stopBit) { if (receiveDataList.Count == 0) break; else { string message = HexEncoding.ToString(receiveDataList.ToArray()); if (message.Length > 0) { _CanMessage.Add(new Message { CANMessage = message }); } startBitFound = false; receiveDataList.Clear(); break; } } } } } public void Write(byte[] data) { clientStream = client.GetStream(); try { clientStream.Write(data, 0, data.Length); } catch { } } } public class HexEncoding { public HexEncoding() { } public static string ToString(byte[] bytes) { string hexString = ""; for (int i = 0; i < bytes.Length; i++) { hexString += bytes[i].ToString("X2"); } return hexString; } } public class ObservableObject : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
<Window x:Class="SampleProj.MainWindow" 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:SampleProj" DataContext="{Binding RelativeSource={RelativeSource Self}}" mc:Ignorable="d" Title="MainWindow" Height="600" Width="525"> <Grid Margin = "0,0,-6.6,-242.2" > < Button Name="conect" Content="Connect" HorizontalAlignment="Left" Margin="119,37,0,0" VerticalAlignment="Top" Width="75" Click="Connect_Button_Click"/> <Button Name = "start" Content="Start Session" HorizontalAlignment="Left" Margin="240,37,0,0" VerticalAlignment="Top" Width="100" Click="Start_Button_Click"/> <ListView ItemsSource = "{Binding Message}" Grid.ColumnSpan="5" Grid.Column="2" HorizontalAlignment="Left" Height="489" Margin="29.4,65.6,0,0" Grid.Row="2" Grid.RowSpan="11" VerticalAlignment="Top" Width="429"> <ListView.View> <GridView> <GridViewColumn Width = " 200" Header="Message" DisplayMemberBinding="{Binding CANMessage}" ></GridViewColumn> </GridView> </ListView.View> </ListView> </Grid> </Window>
这篇关于使用inotifypropertychanged C#WPF更新包含多个字符串的文本框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!