I'm making a program which holds a data of some cryptocurrencies. Howewer I have a problem. If I make data binding like this, it doesn't cause a problem:
//Set binding path to Text property
Binding binding = new Binding("Text");
binding.Source = txt;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.Mode = BindingMode.TwoWay;
//Attach a binding to the listview which holds the data
lst.SetBinding(ListView.SelectedItemProperty, binding);
But if I use below one instead of above one, the TextBlock isn't updating after each property change, it's updated after changing the selected item and selecting the same one:
//Set binding path to SelectedItem property
Binding binding = new Binding("SelectedItem");
binding.Source = lst;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.Mode = BindingMode.TwoWay;
//Attach a binding to the TextBlock which shows the data below the list
txt.SetBinding(TextBlock.TextProperty, binding);
This is the constructor of this project:
public FilteringSample()
{
InitializeComponent();
//Set binding path to Text property
Binding binding = new Binding("Text");
binding.Source = txt;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.Mode = BindingMode.TwoWay;
//Attach a binding to the listview which holds the data
lst.SetBinding(ListView.SelectedItemProperty, binding);
WebClient webClient = new WebClient();
string data1 = webClient.DownloadString("https://www.coingecko.com/tr/coins/solana");
string data2 = webClient.DownloadString("https://www.coingecko.com/tr/coins/bitcoin");
HtmlDocument htmlDocument1 = new HtmlDocument();
HtmlDocument htmlDocument2 = new HtmlDocument();
htmlDocument1.LoadHtml(data1);
string text1= htmlDocument1.DocumentNode.SelectSingleNode("/html/body/div[5]/div[5]/div[1]/div/div[1]/div[3]/div/div[1]/span[1]/span").InnerText;
htmlDocument2.LoadHtml(data2);
string text2 = htmlDocument2.DocumentNode.SelectSingleNode("/html/body/div[5]/div[5]/div[1]/div/div[1]/div[3]/div/div[1]/span[1]/span").InnerText;
ObservableCollection<Currency> list = new ObservableCollection<Currency>();
list.Add(new Currency(){Name="Solana", RealValue = text1 });
list.Add(new Currency() { Name = "Bitcoin", RealValue = text2 });
foreach(Currency cry in list)
{
lst.Items.Add(cry);
}
}
This is the Currency Class that has implemented the INotifyPropertyChanged interface:
public class Currency:INotifyPropertyChanged
{
public string Name { get; set; }
public string Value { get; set; }
public string RealValue
{
get { return Value; }
set
{
if (true)
{
Value = value;
NotifyPropertyChanged("RealValue");
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
public override string? ToString()
{
return Name + " = " + Value;
}
public void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
I used a background worker to update the data every 100 ms, which is the code below:
private void Window_ContentRendered(object sender, EventArgs e)
{
BackgroundWorker backgroundWorker=new BackgroundWorker();
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.DoWork += BackgroundWorker_DoWork;
backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
backgroundWorker.RunWorkerAsync();
}
private void BackgroundWorker_ProgressChanged(object? sender, ProgressChangedEventArgs e)
{
List<string> list = e.UserState as List<string>;
(lst.Items[0] as Currency).RealValue = list[0];
(lst.Items[1] as Currency).RealValue = list[1];
lst.Items.Refresh();
}
private void BackgroundWorker_DoWork(object? sender, DoWorkEventArgs e)
{
WebClient webClient = new WebClient();
while (true)
{
string data1 = webClient.DownloadString("https://min-api.cryptocompare.com/data/price?fsym=sol&tsyms=USD");
string data2 = webClient.DownloadString("https://min-api.cryptocompare.com/data/price?fsym=eth&tsyms=USD");
HtmlDocument htmlDocument1 = new HtmlDocument();
HtmlDocument htmlDocument2 = new HtmlDocument();
htmlDocument1.LoadHtml(data1);
List<string> list=new List<string>() {data1,data2};
(sender as BackgroundWorker).ReportProgress(0,list);
Thread.Sleep(100);
}
}
And the last thing, here is the XAML code:
<Window x:Class="WpfTutorialSamples.ListView_control.FilteringSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="FilteringSample" Height="200" Width="300" Background="Transparent" ContentRendered="Window_ContentRendered"
SizeChanged="Window_SizeChanged">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListView x:Name="lst" ScrollViewer.HorizontalScrollBarVisibility="Hidden" SelectionChanged="lst_SelectionChanged">
<ListView.Resources>
<Style TargetType="ListView">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush>
<GradientStop Color="HotPink" Offset="0"/>
<GradientStop Color="CadetBlue" Offset="0.5"/>
<GradientStop Color="BlanchedAlmond" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</ListView.Resources>
<ListView.View>
<GridView AllowsColumnReorder="False" x:Name="grd">
<GridView.ColumnHeaderContainerStyle>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Foreground" Value="Purple"/>
<Setter Property="FontWeight" Value="ExtraBold"/>
<Setter Property="FontSize" Value="15"/>
<Setter Property="IsHitTestVisible" Value="False"/>
</Style>
</GridView.ColumnHeaderContainerStyle>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="150"/>
<GridViewColumn Header="Value" DisplayMemberBinding="{Binding Value}" Width="Auto"/>
</GridView>
</ListView.View>
</ListView>
<Grid Background="Aqua" Grid.Row="1">
<TextBlock x:Name="txt" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" TextWrapping="Wrap"/>
</Grid>
</Grid>
</Window>
So, what should I do to solve this problem?
If you just want your TextBlock "txt" to Display your Selected Item, the Binding should look like this:
<TextBlock x:Name="txt" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" TextWrapping="Wrap" Text="{Binding ElementName=lst, Path=SelectedItem, Mode=OneWay}"/>
Notice the "Mode=OneWay"? It prevents your TextBlock from setting the ListViews SelectedItem.
You also keep your code-behind free of unnecessary clutter this way.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.