这里相当新手在寻找帮助。
我正在尝试制作一种类似于“ Steam启动器”的东西,但是像当Steam一样,但是当我向文件中添加新游戏时(当前只是为了方便起见,将其存储在文本文件中。
>添加游戏后,除非将DataContext切换到其他视图然后再返回,否则UI不会刷新。
这是主要的3页代码(没有发布完整的内容,请参阅GitHub):((如果出现严重错误,请原谅我)
ListView.xaml
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Game_Launcher.Views"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:ViewModels="clr-namespace:Game_Launcher.ViewModels"
x:Class="Game_Launcher.Views.ListView"
d:DataContext="{d:DesignInstance Type=ViewModels:ListViewModel}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid RenderTransformOrigin="0.693,0.49">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<!-- This section displays a card per game -->
<ScrollViewer VerticalScrollBarVisibility="Auto" Grid.ColumnSpan="3" Grid.RowSpan="7">
<ItemsControl x:Name="gameListView" Grid.ColumnSpan="3" Margin="10,10,0,10" Grid.RowSpan="7" ItemsSource="{Binding Path=games, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<materialDesign:Card Margin="10 5 10 0" Grid.ColumnSpan="3" Grid.RowSpan="5" Height="80">
<Grid>
<Image x:Name="GameIcon" Width="60" HorizontalAlignment="Left" Source="{Binding Icon, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Grid.RowSpan="2" />
<Label x:Name="GameTitle" Content="{Binding Title, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" Margin="65,1,0,45" Width="175" Height="29" FontSize="20" HorizontalAlignment="Left" />
<Label x:Name="GameGenre" Content="{Binding Genres, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="65,35,0,0" RenderTransformOrigin="0.5,0.469" />
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" Margin="72,53,10,0" RenderTransformOrigin="0.5,0.469" FontSize="9">
<Hyperlink NavigateUri="{Binding Link, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" RequestNavigate="Hyperlink_Link">
<TextBlock x:Name="GameLink" Text="{Binding Link, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
</Hyperlink>
</TextBlock>
<Button x:Name="GameLauncher" Click="LaunchButton_OnClick" Tag="{Binding Path, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,16,6,19" Height="40" Width="40" Style="{StaticResource MaterialDesignFloatingActionButton}">
<materialDesign:PackIcon Kind="Gamepad" />
</Button>
</Grid>
</materialDesign:Card>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
ListView.xaml.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using System.Collections.ObjectModel;
using System.IO;
using System.Diagnostics;
using Game_Launcher.ViewModels;
namespace Game_Launcher.Views
{
/// <summary>
/// Interaction logic for ListView.xaml
/// </summary>
public partial class ListView : UserControl
{
private ListViewModel lvm = new ListViewModel();
public ListView()
{
InitializeComponent();
lvm.refreshGames();
gameListView.ItemsSource = lvm.games;
}
//Open web browser when link clicked
private void Hyperlink_Link(object sender, RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
}
//Launch game path when clicked
private void LaunchButton_OnClick(object sender, RoutedEventArgs e)
{
object link = ((Button)sender).Tag;
string linkString = link.ToString().Trim();
Process.Start(new ProcessStartInfo(linkString));
}
}
}
ListViewModel.cs
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
namespace Game_Launcher.ViewModels
{
public class ListViewModel : INotifyPropertyChanged
{
public ObservableCollection<Game> games { get; set; }
public void refreshGames()
{
games = new ObservableCollection<Game>();
if (File.Exists("./Resources/GamesList.txt"))
{
//Read file to gameFile
string gameFile = "./Resources/GamesList.txt";
StreamReader sr = new StreamReader(gameFile, true);
//games is array containing all game info per item
string[] gamesArr = File.ReadAllLines(gameFile);
int numberOfGames = 0;
string[] columns = new string[0];
//columns is array containing each element of the game
foreach (var item in gamesArr)
{
columns = gamesArr[numberOfGames].Split('|');
Game g = new Game
{
Title = columns[0],
Genres = columns[1],
Path = columns[2],
Link = columns[3],
Icon = columns[4],
Poster = columns[5],
Banner = columns[6],
};
games.Add(new Game
{
Title = g.Title,
Genres = g.Genres,
Path = g.Path,
Link = g.Link,
Icon = g.Icon,
Poster = g.Poster,
Banner = g.Banner,
});
numberOfGames++;
}
sr.Close();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Game : INotifyPropertyChanged
{
private string _title;
private string _genres;
private string _path;
private string _link;
private string _icon;
private string _poster;
private string _banner;
public string Title { get { return _title; } set { _title = value; OnPropertyChanged(Title); } }
public string Genres { get { return _genres; } set { _genres = value; OnPropertyChanged(Genres); } }
public string Path { get { return _path; } set { _path = value; OnPropertyChanged(Path); } }
public string Link { get { return _link; } set { _link = value; OnPropertyChanged(Link); } }
public string Icon { get { return _icon; } set { _icon = value; OnPropertyChanged(Icon); } }
public string Poster { get { return _poster; } set { _poster = value; OnPropertyChanged(Poster); } }
public string Banner { get { return _banner; } set { _banner = value; OnPropertyChanged(Banner); } }
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion INotifyPropertyChanged
}
}
答案 0 :(得分:1)
不要在每次填充新ObservableCollection
实例时创建它。只需Clear()
当前实例中的现有项目,然后Add()
将您的新项目集添加到其中。
public ListViewModel()
{
Games = new ObservableCollection<Game>();
}
...
public ObservableCollection<Game> Games { get; }
public void refreshGames()
{
Games.Clear()
...
// add items to Games collection here
}
答案 1 :(得分:-1)
您的问题是您要使用两个单独的视图模型。删除处理ListViewModel
的这些位:
private ListViewModel lvm = new ListViewModel();
public ListView()
{
InitializeComponent();
lvm.refreshGames();
gameListView.ItemsSource = lvm.games;
}
您应该在XAML中创建它的实例:
<UserControl>
<UserControl.DataContext>
<ViewModels:ListViewModel />
</UserControl.DataContext>
</UserControl>